go 中接口与反射

接口与类型

go是静态类型的语言。每个变量都有一种静态类型。换言之,他们的类型在 编译期就确定并且固定下来了。

type MyInt 
var a int 
var b MyInt 

那么 i 的类型为 int ,而 j 的类型为 MyInt 。尽管变量 i 和 j 拥有相同的基本类型, 但它们的静态类型仍然不同,因此在它们未经转换前是不能相互赋值的。 在类型中,有一种重要的类别就是接口类型,它表示一个确定的方法集。只要某个具体值 (非接口)实现了某个接口中的方法,该接口类型的变量就能存储它。

接口的表示

接口类型的变量存储了一对内容:赋予该变量的具体值,以及该值的类型描述符。 更准确地说,其值是实现了该接口的具体数据条目,而其类型则描述了该条目的完整类型。 例如,在执行

var r io.Reader 
tty, _ := os.OpenFile("/dev/tty", os.O_RDWR, 0) 
r = tty 

之后,r 就包含了 (值, 类型) 对,即 ( tty, *os.File )。注意,类型 *os.File 还实现了除 Read 以外的其它方法:尽管该接口值只提供了访问 Read 方法的能力,但其内部却携带了有关该值的所有类型信息。 这就是我们可以这样做的原因:

var w io.Writer 
w = r.(io.Writer) 

在此赋值语句中表达式是一个类型断言: 它断言r内的条目同时实现了io.Writer, 因此我们可以将它赋予w。 w 将会包含一对 ( tty , *os.File )。 这与保存在 r 中的一致。接口的静态类型决定了哪些方法可通过接口变量调用, 即便其内部具体的值可能有更大的方法集。

一个很重要的细节,就是接口内部的对总是 (值, 具体类型) 的形式,而不会是 (值, 接口类型) 的形式。接口不能保存接口值。

三条反射法则

1.反射是从接口值到反射对象

反射只是一种检查存储在接口变量中的"类型-值"的机制,首先,我们需要了解 reflect 包中的两中类型: Type 和 Value,这两种类型可用来访问接口变量的内容。 还有两个简单的函数,叫做 reflect.TypeOf 和 reflect.ValueOf , 它们用于接口值中分别获取 reflect.Type 和 reflect.Value 。 (同样,从 reflect.Value 也能很容易地获取 reflect.Type , 不过让我们先保持 Value 和 Type 概念的独立性吧。

package main 
import ( "fmt" "reflect" ) 
func main() { 
	var x float64 = 3.4 
	fmt.Println("type:", reflect.TypeOf(x)) 
}

当我们调用 reflect.TypeOf(x) 时, x 首先会被存储在一个空接口中, 然后它会作为实参被传入; reflect.TypeOf 通过解包该空接口来还原其类型信息。

reflect.Type 和 reflect.Value 都有许多方法来让我们检测并操作它们。 一个重要的例子就是 Value 拥有一个 Type 方法,它会返回 reflect.Value 的 Type 。另外就是 Type 和 Value 都有一个 Kind 方法,它会返回一个常量来表明条目的类型: Uint 、 Float64 或 Slice 等等。

反射对象的 Kind 描述了其基本类型,而给静态类型。 若反射对象包含了用户定义的整数类型的值,比如

type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)

那么 v 的 Kind 仍为 reflect.Int ,尽管 x 的静态类型为 MyInt 而非 int 。换句话说, Kind 无法区分 int 和 MyInt ,而 Type 则可以。

2.从反射对象可反射出接口值。

通过v.Interface() 可以还原其原接口值

3.设置值

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())

目前会输出

type of p: *float64
settability of p: false

反射对象 p 并不是可设置的,不过我们也不想设置 p , 而(实际上)是 *p 。为获得 p 指向的内容,我们调用 Value 的 Elem 方法,它会间接通过指针,并将结构保存到叫做 v 的反射值 Value 中:

v := p.Elem()
fmt.Println("settability of v:", v.CanSet())

现在 v 是可设置的反射对象,如输出所示:

settability of v: true

总结

反射法则如下

  • 从接口值可反射出反射对象。
  • 从反射对象可反射出接口值
  • 要修改反射对象,其值必须可设置。

转载于:https://my.oschina.net/u/3788834/blog/1858145

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值