接口

来源:互联网 发布:二叉树的前序遍历java 编辑:程序博客网 时间:2024/03/29 22:59
在Go语言中,一个接口类型总是代表着某一种类型(即所有实现它的类型)的行为。一个接口类型的声明通常会包含关键字type、类型名称、关键字interface以及由花括号包裹的若干方法声明。示例如下:


type Animal interface {
    Grow()
    Move(string) string
}
    注意,接口类型中的方法声明是普通的方法声明的简化形式。它们只包括方法名称、参数声明列表和结果声明列表。其中的参数的名称和结果的名称都可以被省略。不过,出于文档化的目的,我还是建议大家在这里写上它们。因此,Move方法的声明至少应该是这样的:


Move(new string) (old string)
    如果一个数据类型所拥有的方法集合中包含了某一个接口类型中的所有方法声明的实现,那么就可以说这个数据类型实现了那个接口类型。所谓实现一个接口中的方法是指,具有与该方法相同的声明并且添加了实现部分(由花括号包裹的若干条语句)。相同的方法声明意味着完全一致的名称、参数类型列表和结果类型列表。其中,参数类型列表即为参数声明列表中除去参数名称的部分。一致的参数类型列表意味着其长度以及顺序的完全相同。对于结果类型列表也是如此。
  
    例如,上一小节(结构体和方法)的延时代码,*Person类型(注意,不是Person类型)就会拥有一个Move方法。该方法会是Animal接口的Move方法的一个实现。再加上在之前为它编写的那个Grow方法,*Person类型就可以被看做是Animal接口的一个实现类型了。
  
    你可能已经意识到,无需在一个数据类型中声明它实现了哪个接口。只要满足了“方法集合为其超集”的条件,就建立了“实现”关系。这是典型的无侵入式的接口实现方法。
  
    好了,现在已经认为*Person类型实现了Animal接口。但是Go语言编译器是否也这样认为呢?这显然需要一种显式的判定方法。在Go语言中,这种判定可以用类型断言来实现。不过,在这里,是不能在一个非接口类型的值上应用类型断言来判定它是否属于某一个接口类型的。必须先把前者转换成空接口类型的值。这又涉及到了Go语言的类型转换。
  
    Go语言的类型转换规则定义了是否能够以及怎样可以把一个类型的值转换另一个类型的值。另一方面,所谓空接口类型即是不包含任何方法声明的接口类型,用interface{}表示,常简称为空接口。正因为空接口的定义,Go语言中的包含预定义的任何数据类型都可以被看做是空接口的实现。可以直接使用类型转换表达式把一个*Person类型转换成空接口类型的值,就像这样:


p := Person{"Robert", "Male", 33, "Beijing"}
v := interface{}(&p)
    请注意第二行。在类型字面量后跟由圆括号包裹的值(或能够代表它的变量、常量或表达式)就构成了一个类型转换表达式,意为将后者转换为前者类型的值。在这里,把表达式&p的求值结果转换成了一个空接口类型的值,并由变量v代表。注意,表达式&p(&是取址操作符)的求值结果是一个*Person类型的值,即p的指针。
  
    在这之后,就可以在v上应用类型断言了,即:


h, ok := v.(Animal)    
    类型断言表达式v.(Animal)的求值结果可以有两个。第一个结果是被转换后的那个目标类型(这里是Animal)的值,而第二个结果则是转换操作成功与否的标志。显然,ok代表了一个bool类型的值。它也是这里判定实现关系的重要依据。
  

    至此,掌握了接口类型、实现类型以及实现关系判定的重要知识和技巧。关于Go语言的类型转换规则的更多细节请参看Go语言规范或《Go并发编程实战》中的相关内容。而至于为什么只有*Person类型才实现了Animal接口,请参看后面两节。

package mainimport "fmt"type Animal interface {    Grow()Move(string) string}type Cat struct {    Name     string    Age      uint8    Location string}func (cat *Cat) Grow() {    cat.Age++}func (cat *Cat) Move(new string) string {    old := cat.Location    cat.Location = new    return old}func main() {myCat := Cat{"Little C", 2, "In the house"}animal, ok := interface{}(&myCat).(Animal)fmt.Printf("%v, %v\n", ok, animal)}


0 0
原创粉丝点击