我有一个实现了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切片的函数。我想念什么?
答案 0 :(得分:1)
专业的Go程序员认为可以对每种类型重复这样的功能,或者对要打印的每个切片都进行for循环是可以的。这是因为Go的目标是尽可能地易于阅读,也就是说,第一次阅读一段代码的人不应问“该函数调用将转到哪个函数重载”之类的问题(C ++中的常见陷阱, Go没有函数重载)。因此,您可以只写main()
:
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)
您可以使用带有接口{}的函数,并使运行时反映类型转换为Stringer切片的类型。请注意,这意味着您仅在运行时不会在编译期间看到类型不匹配:
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)
}
}
资源: