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

2024-03-02

我有以下类型:

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 接口?


a 的内存布局[]Quoteslice 与 a 不同[]Statement切片,所以这是不可能的。

的支持阵列[]Quote切片将由顺序组成Quote结构体,而[]Statementslice 的支持数组由接口变量组成。以及持有Quotestruct(或实现该接口的任何其他类型),接口变量还存储指向所包含值的类型信息的指针。这需要确定如何调度Say方法调用。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • Google Cloud Kubernetes 上任务队列的替代方案

    我发现任务队列主要用于App Engine标准环境 我正在将现有服务从 App Engine 迁移到 Kubernetes 任务队列的一个好的替代方案是什么 推送队列是当前正在使用的队列 我在线阅读文档并浏览了此链接 何时使用 PubSub
  • 如何将对象转换为传递给函数的类型?

    这不会编译 但我想做的只是将对象转换为传递给函数的 t public void My Func Object input Type t t object ab TypeDescriptor GetConverter t ConvertFro
  • 删除接口中的冗余类型

    我有以下接口 public interface IRevision
  • 在 Go 中使用互斥锁

    我想了解互斥体是如何工作的 据我目前的理解 它是为了进行原子操作并同步对某些数据的访问 我在这里构建了一个队列数据结构的示例 https github com arnauddri algorithms blob master data st
  • 我想在后端验证来自 golang 前端的时区

    前端在注册期间发送时区以及其他用户详细信息 我需要在时区上放置一个验证器来进行 api 测试 时区数据的格式为 GMT 10 00 Hawaii GMT 08 00 Pacific Time US amp Canada 我所做的是定义数组中
  • 初始化嵌套匿名结构

    我有一个 json 作为 fields time id status customerId additionalDetail pageInfo start 0 rows 1000 我想将我的结构编组到上面的 json 并创建如下结构 typ
  • php 中接口的用途是什么?

    如果我在 PHP 中定义一个接口 以及一个创建该接口实例的工厂类 有什么方法可以强制客户端代码仅使用该接口而不使用底层具体类 根据我的理解 客户也可以实际使用底层类中的任何公共函数 字段 这是一个例子
  • 让按钮更容易点击

    我有一个按钮 在某些手机上由于尺寸太大而很难点击 但让它变大会破坏布局 可以向视图解释它有一个比其可见区域更大的 点击框 吗 不确定这是否有帮助 如果您使用没有背景的 ImageButton 并设置 Padding 值 您的按钮将具有更大的
  • 是否可以使用显式实现的接口属性对类进行 json 序列化?

    interface A string Name get set interface B string Name get set class C A B string A Name get set string B Name get set
  • GAE Go — 如何对不存在的实体键使用 GetMulti?

    我发现自己需要做一个GetMulti使用键数组进行操作 其中某些实体存在 但有些实体不存在 我当前的代码 如下 返回错误 datastore no such entity err datastore GetMulti c keys info
  • GOPATH值设置

    我用go1 3 1 windows amd64 msi安装go 安装后GOROOT是默认设置 我发现 D Programs Go bin 在 PATH 中 然后我创建一个 GOPATH 环境变量 使用 go get 命令时 出现错误 软件包
  • 在实现接口的类上强制使用单例模式

    我最好用一个例子来解释这个问题 我有一个接口模型可用于访问数据 模型可以有不同的实现 可以以各种格式表示数据 例如 XMl txt 格式等 Model不关心格式 可以说这样的一个实现是myxml模型 现在我想强迫myxml模型以及其他所有实
  • 我怎么知道我的所有 goroutine 确实正在使用 golang 的同步包等待一个条件

    我有一个应用程序 我正在创建多个 goroutine 来同时执行某个任务 所有工作协程都会等待条件 事件发生 一旦事件被触发 它们就会开始执行 创建完所有goroutines后 主线程在发送广播信号之前应该知道所有goroutines确实处
  • 在 C 中如何将一种类型的变量更改为另一种类型?

    我要做 int main bla bla bla void onetype switch USER INPUT TYPE CASE CONVERT TO CHAR convert onetype VOID TO CHAR gt gt gt
  • 鸭子在 Go 中打字

    我想写一个Join函数接受任意对象String 方法 package main import fmt strings type myint int func i myint String string return fmt Sprintf
  • 具有继承类型的 Aux 模式推理失败

    我有一个复杂的玩具算法 我希望纯粹在类型级别上表示 根据饮食要求选择当天菜肴的修改 对卷积表示歉意 但我认为我们需要每一层才能达到我想要使用的最终界面 我的代码有一个问题 如果我们表达一个类型约束Aux 模式生成的类型基于另一个泛型类型 它
  • Golang 正则表达式命名组和子匹配

    我正在尝试匹配正则表达式并获取匹配的捕获组名称 当正则表达式仅与字符串匹配一次时 这是有效的 但如果它与字符串匹配多次 SubexpNames不返回重复的名称 这是一个例子 package main import fmt regexp fu
  • 使用 HTTPS GRC 从 AWS Codecommit 获取私有存储库

    我正在尝试导入位于 AWS codecommit 中的模块 为了克隆存储库 我使用 HTTPS GRC Git 远程代码提交 方法 该方法使用 Google Suite 凭证来访问 AWS 控制台 我用来克隆存储库的命令是 git clon
  • Golang GAE - 小胡子结构中的 intID

    这是一个Example https www dropbox com sh ur2ws1jnik6euef PjVJSwDTUc Blog Golang zip该应用程序的 关键代码在 golang code handler handler
  • 二维数组的 MPI 数据类型

    我需要将一个整数数组的数组 基本上是一个二维数组 从根传递给所有处理器 我在 C 程序中使用 MPI 如何声明二维数组的 MPI 数据类型以及如何发送消息 我应该使用广播还是分散 你需要使用播送 http www netlib org ut

随机推荐