浅谈GO语言中interface

wenjianming · · 1963 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

    接触了go语言已经有几个月的时间了,虽然大部分的系统包还不是很熟练,但是对于go也算是有一定的了解。go语言在语言的层面上并没有非常亮眼的地方。在效率方面,go语言不及c/c++,在移植性上go语言不及java,在高并发方面erlang也能做的很好。所以go会给人有一种很全能的感觉,在各个方面都做了适当的取舍。在开发效率上go会比较快些。

    go语言中,interface是重点。在面向对象设计中,有组合优于继承这句话。go语言放弃了继承,在组合方面表现的很好。首先来看看interface的用法。interface有两种用法:

    1,空接口,用过C/C++的人看了空接口的定义第一时间想到的就是C/C++中的void*。

var Businesser interface{}
var IntData int = 100
var StringData string = "i love hxc" 

Businesser = IntData
var IntData2 int = Businesser.(int)

fmt.Println(Businesser)  // 100
fmt.Println(IntData2)   //100

Businesser = StringData
var StringData2 string = Businesser.(string)
fmt.Println(StringData2) // "i lobe hxc"
fmt.Println(Businesser) // "i love hxc"

    从上面的用法上来看,空接口的用法看起来确实和C/C++中的void*一致。但是在C/C++中一个不知道从何处来的void*类型的变量(当然,从程序设计的角度上看,这种情况是要尽量避免的),我们不能判断它原来的类型,在go语言中对于一个空接口却可以通过类型断言,或者借助系统包中的reflect包对还原出原来赋给空接口的数据类型。

func InterfaceUsage(rhs interface{}) {
    switch val := rhs.(type) {
        case int:
            ...
         case string:
            ...
    }
}

 从上面对空接口的描述可以知道空接口有点类似面向对象语言中的根对象object。然而,在go语言使用interface的时候有一个问题很需要注意。

var Businesser interface{}
var IntData int = 100
var StringData string = "i love hxc" 

Businesser = IntData
var IntData2 int = Businesser.(int)
IntData = 101

fmt.Println(Businesser)  // 100
fmt.Println(IntData2)   //100

Businesser = StringData
StringData = "hxc love me too"
var StringData2 string = Businesser.(string)
fmt.Println(StringData2) // "i lobe hxc"
fmt.Println(Businesser) // "i love hxc"

    从上面代码的输出可以看出在当一个变量赋给一个接口时是将该变量复制一份给空接口。这样就造成了我们看到的变量的内容改变了,空接口保存的变量的内容却不变。要避免这种问题的方法是将变量的地址赋给空接口,这样既保证了两者内容的一致,而且避免了大量的复制工作。该方面的问题在非空接口是一致的。

2,非空接口


    go 语言中并没有显式地支持继承。但是也提供了实现继承的方法,而且实现起来也不是很直观。在go语言中建议使用非空接口。非空接口用法如下:

type Personer interface {
    Walk()
    ChangeName(string)
}

type GoodPerson struct {
    name string
}

func NewGoodPerson(name string) *GoodPerson {
    return &GoodPerson{name}
}

func (this *GoodPerson)Walk() {
    fmt.Println(this.name, " walking")
}

func (this *GoodPerson)ChangeName(name string) {
    this.name = name
}

func (this *GoodPerson)Fly() {
    fmt.Println("man can't fly")
}

func main() {
    var Person Personer = NewGoodPerson("hxc")
    var Person2 interface{} = Person
    
    Person.Walk() // "hxc walking"
    Person.ChangeName("wzm")
    Person.Walk() // "wzm walking"
    // Person.Fly() // error Personer have no field or mothed name Fly
   // Person2.Walk() // error
   //Person = 1 //error
}

    一个数据类型如果实现了接口的方法,那么该数据类型就可以赋值给非空接口。如果该数据类型没有实现非空接口中的方法,那么也是不能赋值给非空接口的。可空接口一样是赋值个接口,其底层会进行拷贝,所以数据类型实现接口的方法是传递指针的比较好。因为这样调用了非空接口就可以改变赋给该非空接口变量的内容。

  在go语言中,一种数据类型无需如其他语言一样显式地说明实现了哪个接口。所以,一种数据类型可以实现多种接口。由于go语言中没有像c++中的构造函数,所以在习惯上go语言都会通过一个工厂产生特定的数据变量。


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:wenjianming

查看原文:浅谈GO语言中interface

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

1963 次点击  
加入收藏 微博
上一篇:Rust and Go
1 回复  |  直到 2000-01-01 00:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传