我有以下类型: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 quotesstatements := make([]Statement, len(conversation))for i, quote := range conversation { statements[i] = quote}Replay(statements)现在说 Replay 是一个库的一部分,它希望能够轻松使用 Replay。只要这些对象实现 Statement 接口,它就允许您使用任何对象切片调用 Replay。为此,它具有以下转换方法: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 接口?
3 回答
慕斯王
TA贡献1864条经验 获得超2个赞
[]Quote
切片的内存布局与切片不同[]Statement
,因此这是不可能的。
所述的背衬阵列[]Quote
片将包括连续的Quote
结构,而[]Statement
片的背衬阵列由接口变量。除了保存Quote
结构体(或任何其他实现接口的类型),接口变量还存储指向所包含值的类型信息的指针。这需要确定如何分派Say
方法调用。
不同的数据布局意味着您不能交换这两种切片类型,即使通过不安全的强制转换也是如此:如果您有一种类型而需要另一种类型,则需要在它们之间手动转换。
莫回无
TA贡献1865条经验 获得超7个赞
对您的(长)问题的简短回答是:不。
我不认为你的 ConvertToStatment 和 Replay 采用空接口的解决方案是一个“不错”的解决方案:我更喜欢func Replay([]Statement)
调用者必须提供一部分 Statments。这更清楚,调用者可以将他们的内容转换为 []Statement 或直接构造一个 []Statement。
- 3 回答
- 0 关注
- 230 浏览
添加回答
举报
0/150
提交
取消