我正在解决《 Go编程语言》一书中的问题,在练习7.13中,需要向String
接口添加方法。
是否可以向String()
接口添加方法?因为直到运行时才知道数据类型。
将方法添加到接口仅意味着将该方法包括在接口类型定义的方法集中。
例如,这是一个接口:
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{}
并且使用类型断言来提取接口的值,则这些类型断言将不再成立。类型断言的“简单”形式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>
如果有可能,现有的具体类型已经具有您刚刚添加到接口中的方法,并且它具有相同的签名(相同的参数和返回类型),那么这很酷,具体类型将“继续”以实现新接口也。如果签名不匹配(例如,现有方法具有不同的返回类型),则它将不满足该接口,并且与不具有相同名称的方法相同。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句