go - 将 []fmt.Stringer 参数传递给函数

标签 go

<分区>

我有一个实现 stringer 接口(interface)的类型

// RowID stores the ID of a single row in a table
type RowID []string

// String implements Stringer interface for RowID
func (r RowID) String() string {
    return fmt.Sprintf("[%s]", strings.Join(r, ", "))
}

我有一个函数,我想将这种类型(或任何其他实现 Stringer 接口(interface)的类型)的 slice 传递给。

// PrintChanges ...
func PrintChanges(ids []fmt.Stringer) {
    for _, id := range ids {
        fmt.Println(id)
    }
}

但是,go 编译器给我一个错误:

cannot use rowIDs (type []RowID) as type []fmt.Stringer in argument to PrintChanges

我可以将 RowID 传递给接受单个 fmt.Stringer 的函数

func PrintChange(id fmt.Stringer) {
    fmt.Println(id)
}

...
    PrintChange(RowID{"1", "24"})

但出于某种原因,我无法将 RowID 的一部分传递给接受 fmt.Stringer 的一部分的函数。我错过了什么?

Go Playground

最佳答案

保持简单

专业的 Go 程序员认为可以为每种类型重复这样的函数,或者对要打印的每个 slice 使用 for 循环。这是因为 Go 旨在尽可能易于阅读,即第一次阅读一大块代码的人不应该问“这个函数调用将转到哪个函数重载”之类的问题(C++ 中的常见陷阱, Go 没有函数重载)。所以你可以在 main() 中写:

Playground :https://ideone.com/IL3rGR

    for _, id := range rowIDs { fmt.Println(id) }

简洁明了。

请注意 fmt.Println(id) 不会调用您的 String() 函数

这是因为 fmt 库使用 reflect 库并对您尝试替换的 string 类型的行为进行硬编码。 RowID 实例也是 string 实例,库总是更喜欢 string 而不是它的类型别名。我会说这是库中的错误:

图书馆来源:https://golang.org/src/fmt/print.go#L649

    // Some types can be done without reflection.
    switch f := arg.(type) {
...
    case string:
        p.fmtString(f, verb)

如果你真的想

您可以使用采用接口(interface){} 并使运行时反射(reflect)类型转换为 Stringer slice 的函数。请注意,这意味着您不会在编译期间看到类型不匹配,只会在运行时看到:

Playground :https://ideone.com/vlrBP9

func castToStringerSlice(iface interface{}) ([]fmt.Stringer, bool /* ok */) {
    if reflect.TypeOf(iface).Kind() != reflect.Slice {
        return nil, false
    }

    v := reflect.ValueOf(iface)
    stringers := make([]fmt.Stringer, v.Len())

    for i := 0; i < v.Len(); i++ {
        stringers[i] = v.Index(i)
    }

    return stringers, true
}

func PrintChanges(iface_ids interface{}) {
    ids, ok := castToStringerSlice(iface_ids)
    if !ok {
        log.Fatal(errors.New("the argument to PrintChanges must be a slice of Stringers"))
    }
    for _, id := range ids {
        fmt.Println(id)
    }
}

资源:

关于go - 将 []fmt.Stringer 参数传递给函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56687894/

相关文章:

go - 如何在 Golang 中为嵌套数组结构初始化变量?

http - 客户端关闭连接时,转到http.ResponseWriter.Write不返回错误

nginx - nginx 自动重生 fastcgi 进程?

map - 在goLang中用函数指针值声明映射

macos - 在 osx 上嗅探 usb 串行通信的方法

go - 在 Golang 中跳过数组的第一个元素

go - 为什么我可以在 go 中重新声明一个 const?

file - 如何验证文件是否包含要从 Go 中的 ioutil.ReadFile 编码的内容

go - golang 中映射的结构有多大?

go - 将 interface{} 转换为 int