Go 中的 interface 所具有的最基本的功能:作为一种 abstract type,实现各种 concrete type 的行为统一。
interface是一种类型。只有是实例化后才能调用interface中的方法,没毛病。
interface的定义
基本形式如下;
1 type (reciever *T) FUNC_NAME (args) (args...Type) { 2 //do something 3 }
interface内部由0个或者多个方法声明组成:
1 /* interface可以没有方法声明 */ 2 type USB interface { 3 } 4 5 /* 多个method声明 */ 6 type USB interface { 7 Name() 8 Age() 9 User() 10 }
也可以嵌套别的interface组合成一个新的interface:
1 type USB interface { 2 Name() string 3 } 4 5 type Computer interface { 6 USB 7 screen(price int) 8 }
以上几种方式都是等价的,但是更推崇嵌入的方式。想下为什么?为了更好的实现多态啊。后面讲。
interface的内部实现初探?
我先实例化上面的interface,然后看一下他所占用的内存大小:(我是在64位操作系统上跑的)
1 var a Computer 2 fmt.Println("sizeof computer = ", unsafe.Sizeof(a)) 3 /* vsizeof computer = 16 */
实际上,所有的interface实例化后都是一样的大小16字节(64位机)。为什么呢?说明interface存放的是一个固定结构,不然大小肯定会变化,就像任何指针变量在64位机上都占8个字节一样。
interface存储的是实例化的值
1 /* declare In interface */ 2 type In interface { 3 Name() string 4 } 5 6 /* declare S struct */ 7 type S struct { 8 x int32 9 y int32 10 } 11 12 /* implement method Name() string with S struct; 13 * Now S struct is an instance of In interface 14 */ 15 func (s S) Name() string { 16 return "interface" 17 } 18 19 /* function print 20 * we can pass an instance of in interface, 21 * we can pass an instance of S struct, too 22 */ 23 func print(in In) { 24 fmt.Println(in.Name()) 25 } 26 27 func main() { 28 s := S{} 29 print(s) //ok 30 31 var i In 32 i = s 33 print(i) //ok 34 }
interface的重要作用体现在func print(in In)中。如果有多种struct实现了interface的methods,那么以interface为接收类型的函数可以接收所有实现了其方法的对象。
这点有点像C++中的父类指针可以接收子类实例作为参数的用法,C++这种做法实现了运行时的多态。
go和C++有所不同的是,go语言不需要显式的告诉编译器我实现了哪些interface,只需要隐式的默默的去实现某个或某些interface的方法即可。go程序运行时候会自动检查并转换。
注意:switch i.(type)语句结构中不能用fallthrough,具体原因不明,有待深入理解。下面这段代码编译会报错:
1 switch value.(type) { 2 case int: 3 fallthrough //error 4 case int64: 5 //...... 6 }
并列写就不会报错了:
1 switch value.(type) { 2 case int, int64: //ok 3 //...... 4 case int int32: 5 //...... 6 }
空interface
go语言和java一样,支持empty interface。看一下下面代码的执行:
1 func main() { 2 var any interface{} 3 any = 1 4 fmt.Println(any) //1 5 any = nil 6 fmt.Println(any) //<nil> 7 any = "string" 8 fmt.Println(any) //string 9 any = S{} 10 fmt.Println(any) //{0 0} 11 }
空的interface没有声明方法,所以所有的类型都实现了interface{},因此所有类型的instance都能当参数传给interface{}的实例。
这个例子还能看出一个奥妙:
不同的类型,实现了同一个接口,那么如果一个类型的方法是另一个方法的子集,那么可以把大的赋值给小的(是赋值还是引用?要进步深入)。
interface的内部实现再探
既然空的 interface 可以接受任何类型的参数,那么一个 interface{}
类型的 slice 是不是就可以接受任何类型的 slice ?
1 s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 2 ss := make([]interface{}, len(s)) 3 ss=s /* error*/ 4 //cannot use s (type []int) as type []interface {} in assignment
竟然报错!!!!go为啥不自动将int转换成interface{}呢?
参考: