golang语言 接口
接口值由动态类型和动态值组成
未初始化的接口类型变量的值为nil,其动态类型和动态值都是nil,调用nil接口值上的方法会产生panic
所有类型都实现了空接口interface{},任意值都能赋给空接口类型
接口里方法的名字必须是唯一的,名字相同,参数或返回值不同,也会报错
接口可以内嵌其他接口,这被称为嵌入接口,不能直接或间接的嵌入自己
Go1.14开始,相同的方法可以被重复嵌入
接收者为指针*T的方法,虽然能用T类型的值去调用,但这只是语法糖,T的方法集里没有该方法,所以T没有实现对应的接口
接口类型 Y 有m方法,编译器会隐式声明一个对应的函数 Y.m,第一个参数的类型为 Y
对于 Y 类型的值 y ,y.m(..) 等价于 Y.m( y, .. )
可以把一个接口类型的变量a赋值给另一个接口类型的变量b,只要a包含b的所有方法 var w io.Writer var rwc io.ReadWriteCloser w = rwc // OK: io.ReadWriteCloser has Write method rwc = w // compile error: io.Writer lacks Close method // 即使w的动态类型实现了read write close三个方法也不行 接口类型封装和隐藏具体类型和它的值。即使具体类型有其它的方法也只有接口的方法能被调用: os.Stdout.Write([]byte("hello")) // OK: *os.File has Write method os.Stdout.Close() // OK: *os.File has Close method var w io.Writer w = os.Stdout // 等价于 w = io.Writer(os.Stdout) w.Write([]byte("hello")) // OK: io.Writer has Write method w.Close() // compile error: io.Writer lacks Close method
类型断言 x.(T)
1,T是具体类型,断言的作用是检查x的动态类型是不是T,若是T,返回T类型的动态值,即返回接口x里的具体值,若不是T,则抛出panic
2,T是接口类型,断言的作用是检查x的动态类型是否实现了T接口,若实现了T,返回值是T类型的接口值,其动态类型以及动态值和x一样,方法集有所改变。失败会panic
如果赋值给两个变量,例如 f, ok := x.(T),在断言失败时不会抛出panic,f是T类型的零值,ok是false
如果x是nil接口值,那么断言总是失败的
类型选择 switch x.(type)
x 必须为接口类型, 而每一个在case中列出的非接口类型 T 必须实现了 x 接口。
类型选择监视可包含一个短变量声明。 当使用此形式时,变量会在每个子句的隐式块的起始处声明。 在case列表只有一个类型的子句中,该变量即拥有此类型;否则,该变量拥有x的类型。
case中的类型可为 nil, 这种情况在类型选择监视中的表达式为 nil 接口值时使用。
类型选择中不能使用fallthrough语句,没有case相当于空操作
switch i := x.(type) { // 也可写为 x := x.(type),或者直接 x.(type) case nil: printString("x is nil") // i 的类型为 x 的类型(interface{}) case int: printInt(i) // i 的类型为 int case float64: printFloat64(i) // i 的类型为 float64 case func(int) float64: printFunction(i) // i 的类型为 func(int) float64 case bool, string: printString("type is bool or string") // i 的类型为 x 的类型(interface{}) default: printString("don't know the type") // i 的类型为 x 的类型(interface{}) } 可被重写为: v := x // x 只被求值一次 if v == nil { i := v // i 的类型为 x 的类型(interface{}) printString("x is nil") } else if i, isInt := v.(int); isInt { printInt(i) // i 的类型为 int } else if i, isFloat64 := v.(float64); isFloat64 { printFloat64(i) // i 的类型为 float64 } else if i, isFunc := v.(func(int) float64); isFunc { printFunction(i) // i 的类型为 func(int) float64 } else { _, isBool := v.(bool) _, isString := v.(string) if isBool || isString { i := v // i 的类型为 x 的类型(interface{}) printString("type is bool or string") } else { i := v // i 的类型为 x 的类型(interface{}) printString("don't know the type") } }
type P struct { } func (p P) add() int { return 1 } type T interface { add() int } m := map[int]int(nil) fmt.Printf("%T\n",m) // map[int]int t := T(nil) fmt.Printf("%T\n",t) // nil tt, ok := t.(T) // nil false var p P t = p fmt.Printf("%T\n",t) // P