文章目录
2.6 interface
interface 类型定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。
interface 可以被任意的对象实现,同理一个对象可以实现任意多个interface.
interface 值
现 interface 就是一组抽象方法的集合,它必须由其他非 interface类型实现,而不能自我实现。
一般就是先定义一个结构体----->>>>然后让该结构体实现一定的方法(method)----->>>把实现的方法定义在一个interface里面
----->>>>如果一个对象实现了interface里面全部的方法就是实现了该接口----->>>此时定义一个interface的变量我们就可以将
定义好的结构体变量的值赋值给接口变量------>>>再调用对应的方法
这个时候我们定义interface 变量的silce就可以把这些接口的值保存在silce。
然后我们可以遍历切片里面的对象调用同一个方法
x[0], x[1], x[2] = paul, sam, mike
for _, value := range x{
value.SayHi()
}
空interface
每一个类型都实现了空接口所以每一种类型都能调用空接口,interface 在我们需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值。
一个函数把 interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数 返回 interface{},那么也就可以返回任意类型的值。
interface 函数参数
通过定义 interface 参数,让函数接受各种类型的参数。
interface 变量存储的类型
判断interface变量存储的类型方法:
• Comma-ok 断言
Go 语言里面有一个语法,可以直接判断是否是该类型的变量: value, ok = element.(T),
这里 value 就是变量的值,ok 是一个 bool 类型,element 是 interface 变量,T 是断言的类
型。
如果 element 里面确实存储了 T 类型的数值,那么 ok 返回 true,否则返回 false。
• switch 测试
switch value := element.(type)
==特别注意:==element.(type)语法不能在 switch 外的任何逻辑里面使用,如果你要在 switch 外面判断一个类型就使用 comma-ok。
嵌入 interface
源码包 container/heap 里面有这样的一个定义
type Interface interface {
sort.Interface //嵌入字段 sort.Interface
Push(x interface{}) //a Push method to push elements into the
heap
Pop() interface{} //a Pop elements that pops elements from the
heap
}
嵌入字段 sort.Interface 所包含的方法
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
反射(浅入未完)
Go 语言实现了反射,所谓反射就是动态运行时的状态。我们一般用到的包是 reflect 包。
使用 reflect 一般分成三步:
1.要去反射是一个类型的值(这些值都实现 了空 interface),首先需要把它转化成 reflect 对象(reflect.Type 或者 reflect.Value,根据不
同的情况调用不同的函数)。
t := reflect.TypeOf(i) //得到类型的元数据,通过 t 我们能获取类型定义里面的所有元素
v := reflect.ValueOf(i) //得到实际的值,通过 v 我们获取存储在里面的值,还可以去改变值
转化为 reflect 对象之后我们就可以进行一些操作了,也就是将 reflect 对象转化成相应的值,
例如
tag := t.Elem().Field(0).Tag //获取定义在 struct 里面的标签
name := v.Elem().Field(0).String() //获取存储在第一个字段里面的值
获取反射值能返回相应的类型和数值
var x float64 = 3.4
// 获取结构体实例的反射类型对象
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())
最后,反射的话,那么反射的字段必须是可修改的,我们前面学习过传值和传引用,这个
里面也是一样的道理,反射的字段必须是可读写的意思是,如果下面这样写,那么会发生
错误
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)
如果要修改相应的值,必须这样写
var x float64 = 3.4
p := reflect.ValueOf(&x)
v := p.Elem()//获取类型元素
v.SetFloat(7.1)
上面只是对反射的简单介绍,更深入的理解还需要自己在编程中不断的实践。