【发布时间】:2016-11-18 11:59:25
【问题描述】:
我正在解决本书The Go Programming Language的问题,
在练习 7.13 中,需要在接口中添加一个String 方法。
是否可以将String() 方法添加到接口?因为直到运行时才知道数据类型。
【问题讨论】:
标签: string methods go interface
我正在解决本书The Go Programming Language的问题,
在练习 7.13 中,需要在接口中添加一个String 方法。
是否可以将String() 方法添加到接口?因为直到运行时才知道数据类型。
【问题讨论】:
标签: string methods go interface
向接口添加方法只是意味着将该方法包含在接口类型定义的方法集中。
例如这是一个接口:
type Fooer interface {
Foo()
}
它有一种方法:Foo()。将String()方法添加到这个接口:
type Fooer interface {
Foo()
String() string
}
完成。我们在这个接口中添加了String() 方法。
这样的结果是,如果一个具体类型想要实现这个Fooer 接口,以前只需要一个Foo() 方法就足够了。现在它还必须有一个String() 方法。
还要注意,在 Go 中实现接口是隐式的。 没有意图声明。如果一个类型具有接口的所有方法,则它隐式地满足接口。
具体类型可能有也可能没有String() 方法,独立于我们的Fooer 接口。具体类型可能甚至不知道我们的Fooer 接口,它也不需要。
这是一个实现Fooer 接口的具体类型:
type fooerImpl int
func (f fooerImpl) Foo() {
fmt.Printf("Foo() called, I'm %d\n", int(f))
}
func (f fooerImpl) String() string {
return fmt.Sprintf("Foo[%d]", int(f))
}
测试它:
var f Fooer = fooerImpl(3)
f.Foo()
fmt.Println(f.String())
fmt.Println(f)
输出(在Go Playground 上试试):
Foo() called, I'm 3
Foo[3]
Foo[3]
如果你在一个接口中随意添加一个新方法,可能会导致之前实现该接口的某些现有具体类型不再实现它(由于缺少新添加的方法)。
如果这些现有的具体类型被用作接口的实例,它们将导致编译时错误,并且在您添加缺少的新方法之前将无法工作。例如,如果我们从上面的示例中删除fooerImpl.String() 方法,代码var f Fooer = fooerImpl(3) 会导致编译时错误:
cannot use fooerImpl(3) (type fooerImpl) as type Fooer in assignment:
fooerImpl does not implement Fooer (missing String method)
如果现有的具体类型没有直接用作接口的实例,而是例如它们被包裹在空接口interface{} 中传递,type assertion 用于提取接口的值,这些类型断言将不再持有。类型断言x.(T) 的“简单”形式将导致运行时恐慌,特殊形式v, ok := x.(T) 将返回nil 和false。
例如使用上面的fooerImpl 类型而不使用String() 方法:
var f0 interface{} = fooerImpl(3)
f := f0.(Fooer)
导致运行时恐慌:
panic: interface conversion: main.fooerImpl is not main.Fooer: missing method String
并使用类型转换的特殊形式:
if f, ok := f0.(Fooer); ok {
f.Foo()
} else {
fmt.Println("Not instance of Fooer!", f)
}
结果:
Not instance of Fooer! <nil>
如果现有的具体类型已经有一个您刚刚添加到接口的方法并且它具有相同的签名(相同的参数和返回类型),那么这很酷,具体类型将“继续”实现新界面也是。如果签名不匹配(例如现有方法的返回类型不同),则不满足接口,与没有同名方法相同。
【讨论】: