为了账号安全,请及时绑定邮箱和手机立即绑定

调用 Go 函数,该函数接受接口 A 的切片和结构 B 的切片(B 实现 A)

调用 Go 函数,该函数接受接口 A 的切片和结构 B 的切片(B 实现 A)

Go
有只小跳蛙 2021-06-30 13:08:43
我有以下类型: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方法调用。

不同的数据布局意味着您不能交换这两种切片类型,即使通过不安全的强制转换也是如此:如果您有一种类型而需要另一种类型,则需要在它们之间手动转换。


查看完整回答
反对 回复 2021-07-12
?
莫回无

TA贡献1865条经验 获得超7个赞

对您的(长)问题的简短回答是:不。

我不认为你的 ConvertToStatment 和 Replay 采用空接口的解决方案是一个“不错”的解决方案:我更喜欢func Replay([]Statement)调用者必须提供一部分 Statments。这更清楚,调用者可以将他们的内容转换为 []Statement 或直接构造一个 []Statement。


查看完整回答
反对 回复 2021-07-12
  • 3 回答
  • 0 关注
  • 230 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信