接口的特色
var r io.Reader
tty, err = os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil { return nil, err }
r = tty
var w io.Writer
w = r.(io.Writer)
- tty 是*os.File 类型。此类型实现了io.Reader中的Read()和io.Writer()中的Write()方法 以及一些其他的方法。所以可以进行赋值。
- 接口类型的变量存储了两个内容:赋值给变量实际的值和这个值的类型描述。即(value,type)对。更准确的说,值是底层实现了接口的实际数据项目,而类型描述了这个项目完整的类型。
反射三原则-1-从接口值到反射对象的反射。
reflect.TypeOf 反射出对象的类型
reflect.ValueOf 反射出对象的值
type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)
v.Kind() = reflect.Int != reflect.MyInt
- 反射对象的 Kind 描述了底层类型,而不是静态类型。如果一个反射对象包含了用户定义的整数类型的值 。
- v 的 Kind 仍然是 reflect.Int,尽管 x 的静态类型是 MyInt,而不是 int。换句话说,Kind 无法从 MyInt 中区分 int,而 Type 可以。
反射三原则-2-从反射对象到接口值的反射。
从 reflect.Value 可以使用 Interface() 方法还原接口值。
简单来说,Interface 方法是 ValueOf 函数的镜像。
其实我不明白为啥要这个东西。
反射三原则-3-为了修改反射对象,其值必须可设置。
也就是在Set值之前调用CanSet()去判断。
可以肯定的是,我们在修改反射对象之前,必须传它的指针,
因为传值没有意义,会发生复制。也就是再怎么set 也不是原来的对象了。如下:
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.
虽然 v 看起来是从 x 创建的,它也无法更新 x。反之,如果在反射值内部允许更新 x 的副本,那么 x 本身不会收到影响。这会造成混淆,并且毫无意义,因此这是非法的,而设置性是用于解决这个问题的属性。
这很神奇?其实不是。这实际上是一个常见的非同寻常的情况。 就是值传递和指针传递。
下面就不会错。
var x float64 = 3.4
p := reflect.ValueOf(&x) // 注意:获取 X 的地址。
fmt.Println("type of p:", p.Type())
v := p.Elem()
fmt.Println("settability of p:" , v.CanSet())
引用:
https://mikespook.com/2011/09/%e5%8f%8d%e5%b0%84%e7%9a%84%e8%a7%84%e5%88%99/
网友评论