【发布时间】:2013-12-08 10:37:54
【问题描述】:
我有以下几种:
type Statement interface {
Say() string
}
type Quote struct {
quote string
}
func (p Quote) Say() string {
return p.quote
}
func Replay(conversation []Statement) {
for _, statement := range conversation {
fmt.Println(statement.Say())
}
}
我想我已经很好地理解了为什么一个接受[]Statement 类型参数的函数不能用[]Quote 调用;即使Quote 实现了Statement,[]Quote 也没有实现[]Statement。 []Statement 甚至不是一个接口。它的类型为slice of Statement。虽然 Go 隐式地将类型转换为接口类型,但它不会将类型为 A 的切片隐式转换为接口 B 的切片。
我们可以将引号显式转换为语句:
conversation := []Quote{
Quote{"Nice Guy Eddie: C'mon, throw in a buck!"},
Quote{"Mr. Pink: Uh-uh, I don't tip."},
Quote{"Nice Guy Eddie: You don't tip?"},
Quote{"Mr. Pink: Nah, I don't believe in it."},
Quote{"Nice Guy Eddie: You don't believe in tipping?"},
}
// This doesn't work
// Replay(conversation)
// Create statements from quotes
statements := make([]Statement, len(conversation))
for i, quote := range conversation {
statements[i] = quote
}
Replay(statements)
现在说,Replay 是一个库的一部分,它希望不妨碍它使用 Replay 的简单性。它允许您使用任何对象切片调用 Replay,只要这些对象实现 Statement 接口即可。为此,它具有以下转换方法:
func ConvertToStatements(its interface{}) ([]Statement, error) {
itsValue := reflect.ValueOf(its)
itsKind := itsValue.Kind()
if itsKind != reflect.Array && itsKind != reflect.Slice {
return nil, fmt.Errorf("Expected items to be an Array or a Slice, got %s", itsKind)
}
itsLength := itsValue.Len()
items := make([]Statement, itsLength)
for i := 0; i < itsLength; i++ {
itsItem := itsValue.Index(i)
if item, ok := itsItem.Interface().(Statement); ok {
items[i] = item
} else {
return nil, fmt.Errorf("item #%d does not implement the Statement interface: %s", i, itsItem)
}
}
return items, nil
}
回放看起来像这样:
func Replay(its interface{}) {
conversation := ConvertToStatements(its)
for _, statement := range conversation {
fmt.Println(statement.Say())
}
}
我们现在可以直接用引号调用 Replay:
Replay(conversation)
最后,我的问题是:有没有更简单的方法可以让 Replay 接受任何类型 A 的切片,只要 A 实现 Statement 接口?
【问题讨论】: