我正在解决这本书The Go Programming Language的问题,
在练习7.13中,需要在接口中添加String
方法。
是否可以向接口添加String()
方法?因为直到运行时才知道数据类型。
答案 0 :(得分:3)
向接口添加方法只是意味着将该方法包含在接口类型定义的方法集中。
例如,这是一个界面:
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>
如果现有的具体类型已经有了一个刚刚添加到接口的方法并且它具有相同的签名(相同的参数和返回类型),那么很酷,具体类型将“继续”实现新的界面也是。如果签名不匹配(例如,现有方法具有不同的返回类型),则它将不满足接口,并且与没有具有相同名称的方法相同。