【问题标题】:Passing a []fmt.Stringer parameter to a func [duplicate]将 []fmt.Stringer 参数传递给 func [重复]
【发布时间】:2019-11-03 09:17:47
【问题描述】:

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

// 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 接口的类型)传递给。

// 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


【解决方案1】:

保持简单

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

游乐场: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)

如果你真的想

您可以使用一个函数,该函数接受一个接口{},并将运行时反射类型转换为 Stringers 切片。请注意,这意味着您不会在编译期间看到类型不匹配,只会在运行时看到:

游乐场: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)
    }
}

资源:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2017-06-10
    • 2018-06-27
    相关资源
    最近更新 更多