• 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

  • 相关阅读:
    NFS共享储存
    Rsync服务
    企业集群架构概述
    定时任务
    开机启动流程
    进程管理(二)
    linux系统管理-进程管理
    RAID&LVM有关磁盘的故障
    gdisk分区及swap分区
    操作系统与磁盘管理
  • 原文地址:https://www.cnblogs.com/howo/p/9057972.html
Copyright © 2020-2023  润新知