golang入门day7(CSP 并发模型 + 反射)

什么是CSP并发模型:

严格的说CSP 应该是一门形式语言: 用于描述并发系统的互动模式。

CSP 中文名称叫 通信顺序进程, 是一个 很强大的并发编程模型,是Go语言成功的中重要因素 : go语言并未完全使用CSP模型, 而仅仅使用了 process 和 channel两个概念

process : 在go语言中 即 goroutine

go语言使程序员开发时 更轻松, 而不用考虑 线程数 ,线程 开销,线程调度 等底层问题,goroutine天生就为我们实现好了。

goroutine 和channel是 go语言 并发编程的两大基石: goroutine 负责执行并发业务, 而channel 用于goroutine之间的同步通信。 goroutine 是 线程安全的

go的并发哲学

不要使用共享内存 来通信, 而要通过通信来实现共享内存。
意味着我们不要 借助 sync包实现并发编程,而强烈建议通过channel实现并发编程。

四 Goroutine:

Goroutine是实际并发执行的实体:底层通过 coroutine(协程)来实现并发, 协程是一种运行在用户态的线程, go底层使用协程的出发点是因为:协程具有以下特点:
1 使用的是用户空间,避免了 用户态和内核态切换的开销
2 可以由语言或框架进行调度
3 协程具有更小栈空间, 那么允许创建大量的协程实例

反射初识

反射就是在程序运行是时,能够观察自己, 并修改自己的行为的一种机制。

反射是和接口类型相关的 , 只有interface 类型才有反射这一说

要理解反射 ,就得理解 接口的pair 属性 。

pair(实体值, 类型)

反射 实质: 在运行时,能够动态的获取 接口的 值 和类型, 进而进行一些其他的操作。

reflect包 :下 TypeOf() 和 ValueOf ()

1 现有 接口类型变量
2 转化为 reflect 类型
3 通过接口来获取

package main

import (
	"fmt"
	"reflect"
)

func main(){
	var a float64 = 4.13  // int64 类型 可以看作是一个 空接口类型, 所以可以直接使用
	fmt.Println("type:",reflect.TypeOf(a))
}
需要反射的两个场景:

1 有时候编写的函数, 不知道需要接受什么类型,
2 有时候需要根据某些条件来决定调用哪个函数,比如由用户的输入来确定, 这时候就需要对函数和函数的参数进行反射,在运行期间动态的执行函数。

在这里插入图片描述

package main

import (
	"fmt"
	"reflect"
)

func main(){
	var num float64 =1.23
	// 由接口类型变量  -->得到反射类型对象
	value := reflect.ValueOf(num)
	fmt.Println("由接口类型变量  --> 得到反射类型对象 : ",value)
	convertValue := value.Interface().(float64)
	fmt.Println("由反射类型对象  --> 转化得到接口类型变量:",convertValue)
	fmt.Printf("%T\n",convertValue)
}

注意下边代码只是用来检验 反射 ,并不是说这样写更科学

在这里插入图片描述

package main

import (
	"fmt"
	"reflect"
)
type Person struct{
	Name string
	Age int
	Sex string
}

func (p Person)printInfo(){
	fmt.Println(p.Name, " ", p.Age," ", p.Sex)
}
func (p Person)readInfo(){
	fmt.Println("Name :",p.Name, "Age :", p.Age,"Sex :", p.Sex)
}

func testReflect(p interface{}){
	fmt.Println("P is :", p)// 检验普通做法

	//检验 反射 做法
	getValue := reflect.ValueOf(p)
	getType := reflect.TypeOf(p)
	fmt.Println("reflect  value is : ", getValue)
	fmt.Println("reflect  type  is : ", getType)
	i :=  getValue.Kind()
	fmt.Println("value kind is :", i)
	/*
		获取 p的字段
	*/

	for i:=0; i < getType.NumField(); i++{
		field := getType.Field(i)
		fmt.Println("字段名称:",field.Name,"字段类型:", field.Type,
			"字段数值:",getValue.Field(i).Interface())
	}
}

func main(){
	/*
	var num float64 =1.23
	// 由接口类型变量  -->得到反射类型对象
	value := reflect.ValueOf(num)
	fmt.Println("由接口类型变量  --> 得到反射类型对象 : ",value)
	convertValue := value.Interface().(float64)
	fmt.Println("由反射类型对象  --> 转化得到接口类型变量:",convertValue)
	fmt.Printf("%T\n",convertValue)
	 */
	p := Person{"小二",19,"男"}
	testReflect(p)
}

反射对象.Kind() 是说种类 :eg: slice 、 map、 pointer、 struct、interface、 array\ Function 、int等等

Type()是说类型: 比如 : Person 类 等

比如
type Person struct {

}

那么 Kind 就是 struct 而 Type 是 Person

如何通过反射对象 设置 实际变量的值?

** 注意的是: 需要修改 必须拿到指针。才可以修改**

在这里插入图片描述

设置实际变量的值 : 指针方式

package main

import (
	"fmt"
	"reflect"
)

func main(){
	 var num float64 =1.23
	 fmt.Println("num->",num)
	 pointer:= reflect.ValueOf(&num)
	 newValue := pointer.Elem()//获取指针指向的反射对象(原始对象)
	 fmt.Println("newValue -> ",newValue)
	 fmt.Println("newValue类型-->",newValue.Type())
	 fmt.Println("newValue种类-->",newValue.Kind())
	 fmt.Println("newValue是否可以修改对象:",newValue.CanSet())
	 newValue.SetFloat(3.14)
	 fmt.Println("newValue is ->",newValue)
	 fmt.Println("num is->",num)
}

注意:

1 要通过 反射来调用对应的方法,必须先通过reflect.ValueOf()获取到 “反射类型的对象“后才能做下一步处理,

2 反射类型对象.MethodByName() 这个 MethodByName,需要指定准确的真实的方法名字, 错了就会直接panic, MethodByName 返回一个函数值对应的reflect.Value(反射类型对象)方法的名字
3 【】reflect.Value, 是最重要调用的方法的参数, 我们用切片进行存储, 空的时候也可以传nil

4 反射类型对象的Call 方法,这个方法最终调用真实的方法,参数必须保持一致, 如果反射类型对象.Kind不是一个方法, 那么直接panic

5 ( 本来可以用对象直接调用方法的) 我们采用反射,首先得将方法注册,也就是MethodByName, 然后通过反射调用methodValue.Call

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值