go语言interface学习

 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{}呢?

 

 

 

 

参考:

Go Data Structures: Interfaces

 

posted @ 2018-05-18 20:48  guhowo  阅读(466)  评论(0编辑  收藏  举报