接口与反射
接口(interface)
简介
- 方法的集合
- 一种类型,并且是指针类型
- 实现多态的作用
- 可以包含一组方法,但是不需要实现
- 接口不仅仅是针对结构体,自定义类型,变量等等都可以实现接口
- 没有任何方法的接口称之为空接口,所以任何类型都是现实空接口
- 要实现一个接口,必须实现里面的所有方法
定义
type 接口名称 interface {
method1 (参数列表) 返回值列表
method2 (参数列表) 返回值列表
...
}
使用
package main
import (
"fmt"
)
// 定义接口
type Person interface{
Run()
GetName() string
}
type Student struct{
Name string
Age int
}
//实现getname方法
func (s Student) GetName()string{
fmt.Println(s.Name)
return s.Name
}
// 实现run方法
func (s Student) Run() {
fmt.Printf("%s run",s.Name)
}
func main() {
var p Person
var s Student
s.Name="jet"
s.Age=23
p=s
p.Run()// 调用接口
}
多态
接口是多态的一种形式,就是事物的多种形式,同一个接口,不同的类型实现,都可以进行调用
一个接口2个实现
package main
import (
"fmt"
)
// 定义接口
type Person interface{
Run()
GetName() string
}
type Student struct{
Name string
Age int
}
type Teacher struct{
Name string
Salary int// 薪资
}
//实现getname方法
func (s Student) GetName()string{
fmt.Println(s.Name)
return s.Name
}
// 实现run方法
func (s Student) Run() {
fmt.Printf("%s 学生实现的run ",s.Name)
}
// 老师实现 getname
func (t Teacher) GetName()string{
fmt.Println(t.Name)
return t.Name
}
//老师实现run
func (t Teacher) Run(){
fmt.Printf("\n %s 老师实现的run ",t.Name)
}
func main() {
var p Person
var s Student
var t Teacher
t.Name="张三"
s.Name="jet"
s.Age=23
p=s
p.Run()// 调用接口
p=t
t.Run()
}
嵌套
type Skills interface {
Running()
Getname() string
}
type Test interface {
sleeping()
Skills //继承Skills
}
反射 reflect
反射是程序执行时检查其所拥有的结构,是类型的一种能力。go语言的反射是通过reflect包实现了运行时的反射,允许程序操作任意类型的对象
Type
用来表示一个go的类型, 不是所有的Type的值都能使用所有方法
获取type对象的方法
func TypeOf(i interface{}) Type
实例
package main
import (
"fmt"
"reflect"
)
func main() {
str:="Jet"
res_type:=reflect.TypeOf(str)
fmt.Println(res_type)
}
reflect.Type
通用方法
// 通用方法
func (t *rtype) String() string // 获取 t 类型的字符串描述,不要通过 String 来判断两种类型是否一致。
func (t *rtype) Name() string // 获取 t 类型在其包中定义的名称,未命名类型则返回空字符串。
func (t *rtype) PkgPath() string // 获取 t 类型所在包的名称,未命名类型则返回空字符串。
func (t *rtype) Kind() reflect.Kind // 获取 t 类型的类别。
func (t *rtype) Size() uintptr // 获取 t 类型的值在分配内存时的大小,功能和 unsafe.SizeOf 一样。
func (t *rtype) Align() int // 获取 t 类型的值在分配内存时的字节对齐值。
func (t *rtype) FieldAlign() int // 获取 t 类型的值作为结构体字段时的字节对齐值。
func (t *rtype) NumMethod() int // 获取 t 类型的方法数量。
func (t *rtype) Method() reflect.Method // 根据索引获取 t 类型的方法,如果方法不存在,则 panic。
// 如果 t 是一个实际的类型,则返回值的 Type 和 Func 字段会列出接收者。
// 如果 t 只是一个接口,则返回值的 Type 不列出接收者,Func 为空值。
func (t *rtype) MethodByName(string) (reflect.Method, bool) // 根据名称获取 t 类型的方法。
func (t *rtype) Implements(u reflect.Type) bool // 判断 t 类型是否实现了 u 接口。
func (t *rtype) ConvertibleTo(u reflect.Type) bool // 判断 t 类型的值可否转换为 u 类型。
func (t *rtype) AssignableTo(u reflect.Type) bool // 判断 t 类型的值可否赋值给 u 类型。
func (t *rtype) Comparable() bool // 判断 t 类型的值可否进行比较操作
####注意对于:数组、切片、映射、通道、指针、接口
func (t *rtype) Elem() reflect.Type // 获取元素类型、获取指针所指对象类型,获取接口的动态类型
实例
package main
import (
"fmt"
"reflect"
)
type Person interface{
reading()
running()
}
type Student struct{
Name string
Age int
}
func(s Student) reading(){
fmt.Printf("%s is reading \n", s.Name)
}
func(s Student) running(){
fmt.Printf("%s is running \n", s.Name)
}
func main() {
s1:=Student{ Name:"Jet",Age:23}
p:=new(Person)
s_type:=reflect.TypeOf(s1)
p_type:=reflect.TypeOf(p).Elem() //引用类型需要用Elem() 获取指针所指向的对象类型
fmt.Println(s_type.String()) //main.Student
fmt.Println(s_type.Name()) //Student
fmt.Println(s_type.PkgPath()) //main
fmt.Println(s_type.Kind()) //struct 类型的类别
fmt.Println(s_type.Size()) //24 分配内存的大小
fmt.Println(p_type.NumMethod()) //2 获取方法的数量
fmt.Println(p_type.Method(0),p_type.Method(0).Name) // reading
fmt.Println(p_type.MethodByName("reading")) // 根据类型获取方法
fmt.Println("==========其他方法================")
fmt.Println(s_type.NumField()) //2 字段数量
fmt.Println(s_type.Field(0)) //{Name string 0 [0] false} 第一个字段
fmt.Println(s_type.FieldByName("Age")) // 根据名称获取结构体的字段,不存在返回reflect.ValueOf(nil)
}
其它方法
// 数值
func (t *rtype) Bits() int // 获取数值类型的位宽,t 必须是整型、浮点型、复数型
------------------------------
// 数组
func (t *rtype) Len() int // 获取数组的元素个数
------------------------------
// 映射
func (t *rtype) Key() reflect.Type // 获取映射的键类型
------------------------------
// 通道
func (t *rtype) ChanDir() reflect.ChanDir // 获取通道的方向
------------------------------
// 结构体
func (t *rtype) NumField() int // 获取字段数量
func (t *rtype) Field(int) reflect.StructField // 根据索引获取字段
func (t *rtype) FieldByName(string) (reflect.StructField, bool) // 根据名称获取字段
func (t *rtype) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool) // 根据指定的匹配函数 math 获取字段
func (t *rtype) FieldByIndex(index []int) reflect.StructField // 根据索引链获取嵌套字段
------------------------------
// 函数
func (t *rtype) NumIn() int // 获取函数的参数数量
func (t *rtype) In(int) reflect.Type // 根据索引获取函数的参数信息
func (t *rtype) NumOut() int // 获取函数的返回值数量
func (t *rtype) Out(int) reflect.Type // 根据索引获取函数的返回值信息
func (t *rtype) IsVariadic() bool // 判断函数是否具有可变参数。
// 如果有可变参数,则 t.In(t.NumIn()-1) 将返回一个切片。
Value
value 为go提供了反射接口
func ValueOf(i interface{}) Value
reflect.Value
reflect.Value.Kind() 获取变量类别的,返回常量
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
用于获取值的方法
func (v Value) Int() int64 // 获取int类型值,如果 v 值不是有符号整型,则 panic。
func (v Value) Uint() uint64 // 获取unit类型的值,如果 v 值不是无符号整型(包括 uintptr),则 panic。
func (v Value) Float() float64 // 获取float类型的值,如果 v 值不是浮点型,则 panic。
func (v Value) Complex() complex128 // 获取复数类型的值,如果 v 值不是复数型,则 panic。
func (v Value) Bool() bool // 获取布尔类型的值,如果 v 值不是布尔型,则 panic。
func (v Value) Len() int // 获取 v 值的长度,v 值必须是字符串、数组、切片、映射、通道。
func (v Value) Cap() int // 获取 v 值的容量,v 值必须是数值、切片、通道。
func (v Value) Index(i int) reflect.Value // 获取 v 值的第 i 个元素,v 值必须是字符串、数组、切片,i 不能超出范围。
func (v Value) Bytes() []byte // 获取字节类型的值,如果 v 值不是字节切片,则 panic。
func (v Value) Slice(i, j int) reflect.Value // 获取 v 值的切片,切片长度 = j - i,切片容量 = v.Cap() - i。
// v 必须是字符串、数值、切片,如果是数组则必须可寻址。i 不能超出范围。
func (v Value) Slice3(i, j, k int) reflect.Value // 获取 v 值的切片,切片长度 = j - i,切片容量 = k - i。
// i、j、k 不能超出 v 的容量。i <= j <= k。
// v 必须是字符串、数值、切片,如果是数组则必须可寻址。i 不能超出范围。
func (v Value) MapIndex(key Value) reflect.Value // 根据 key 键获取 v 值的内容,v 值必须是映射。
// 如果指定的元素不存在,或 v 值是未初始化的映射,则返回零值(reflect.ValueOf(nil))
func (v Value) MapKeys() []reflect.Value // 获取 v 值的所有键的无序列表,v 值必须是映射。
// 如果 v 值是未初始化的映射,则返回空列表。
func (v Value) OverflowInt(x int64) bool // 判断 x 是否超出 v 值的取值范围,v 值必须是有符号整型。
func (v Value) OverflowUint(x uint64) bool // 判断 x 是否超出 v 值的取值范围,v 值必须是无符号整型。
func (v Value) OverflowFloat(x float64) bool // 判断 x 是否超出 v 值的取值范围,v 值必须是浮点型。
func (v Value) OverflowComplex(x complex128) bool // 判断 x 是否超出 v 值的取值范围,v 值必须是复数型。
设置值的方法
func (v Value) SetInt(x int64) //设置int类型的值
func (v Value) SetUint(x uint64) // 设置无符号整型的值
func (v Value) SetFloat(x float64) // 设置浮点类型的值
func (v Value) SetComplex(x complex128) //设置复数类型的值
func (v Value) SetBool(x bool) //设置布尔类型的值
func (v Value) SetString(x string) //设置字符串类型的值
func (v Value) SetLen(n int) // 设置切片的长度,n 不能超出范围,不能为负数。
func (v Value) SetCap(n int) //设置切片的容量
func (v Value) SetBytes(x []byte) //设置字节类型的值
func (v Value) SetMapIndex(key, val reflect.Value) //设置map的key和value,前提必须是初始化以后,存在覆盖、不存在添加
其它方法
##########结构体相关:
func (v Value) NumField() int // 获取结构体字段(成员)数量
func (v Value) Field(i int) reflect.Value //根据索引获取结构体字段
func (v Value) FieldByIndex(index []int) reflect.Value // 根据索引链获取结构体嵌套字段
func (v Value) FieldByName(string) reflect.Value // 根据名称获取结构体的字段,不存在返回reflect.ValueOf(nil)
func (v Value) FieldByNameFunc(match func(string) bool) Value // 根据匹配函数 match 获取字段,如果没有匹配的字段,则返回零值(reflect.ValueOf(nil))
########通道相关:
func (v Value) Send(x reflect.Value)// 发送数据(会阻塞),v 值必须是可写通道。
func (v Value) Recv() (x reflect.Value, ok bool) // 接收数据(会阻塞),v 值必须是可读通道。
func (v Value) TrySend(x reflect.Value) bool // 尝试发送数据(不会阻塞),v 值必须是可写通道。
func (v Value) TryRecv() (x reflect.Value, ok bool) // 尝试接收数据(不会阻塞),v 值必须是可读通道。
func (v Value) Close() // 关闭通道
########函数相关
func (v Value) Call(in []Value) (r []Value) // 通过参数列表 in 调用 v 值所代表的函数(或方法)。函数的返回值存入 r 中返回。
// 要传入多少参数就在 in 中存入多少元素。
// Call 即可以调用定参函数(参数数量固定),也可以调用变参函数(参数数量可变)。
func (v Value) CallSlice(in []Value) []Value // 调用变参函数
简单结构体的操作
func main() {
s1:=Student{ Name:"Jet",Age:23}
s_val:=reflect.ValueOf(s1) //获取value的类型
fmt.Println(s_val.NumField()) //2
fmt.Println(s_val.Field(0),s_val.Field(1)) //wd 22
fmt.Println(s_val.FieldByName("Age")) //22
s_val2 := reflect.ValueOf(&s1).Elem()
s_val2.FieldByName("Age").SetInt(33) //设置字段值 ,结果33
fmt.Println(s1.Age)
}
获取和设置普通类型的值
func main() {
str := "Jet"
age := 11
fmt.Println(reflect.ValueOf(str).String()) //获取str的值,结果wd
fmt.Println(reflect.ValueOf(age).Int()) //获取age的值,结果age
str2 := reflect.ValueOf(&str) //获取Value类型
str2.Elem().SetString("jack") //设置值
fmt.Println(str2.Elem(),age) //jack 11
}
通过反射调用结构体中的方法
通过reflect.Value.Method(i int).Call()或者reflect.Value.MethodByName(name string).Call()实现
package main
import (
"fmt"
"reflect"
)
type Student struct{
Name string
Age int
}
func (this *Student) SetName(name string){
this.Name=name
fmt.Printf("设置了 %s \n",this.Name)
}
func (this *Student) SetAge(age int) {
this.Age = age
fmt.Printf("set age %d\n",age )
}
func (this *Student) String() string {
fmt.Printf("this is %s\n",this.Name)
return this.Name
}
func main() {
stu1 := &Student{Name:"wd",Age:22}
val := reflect.ValueOf(stu1) //获取Value类型,也可以使用reflect.ValueOf(&stu1).Elem()
val.MethodByName("String").Call(nil) //调用String方法
params := make([]reflect.Value, 1)
params[0] = reflect.ValueOf(18)
val.MethodByName("SetAge").Call(params) //通过名称调用方法
params[0] = reflect.ValueOf("jack")
val.Method(1).Call(params) //通过方法索引调用
fmt.Println(stu1.Name,stu1.Age)
}