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

切片和接口的类型转换

切片和接口的类型转换

Go
长风秋雁 2022-08-01 15:15:58
如果我传递了一个函数,我可以确定(通过其他方式)是一个切片,但不是它是什么切片,我该如何迭代它(最好不使用反射)?interface{}这是一个MCVE(从我的实际代码中非常简化)。 是一个循环访问切片的函数,其类型在 main() 的调用堆栈中“丢失”。它试图说“啊哈,一个切片,我将循环访问它的一个接口切片{},并在每个值上调用传入的onEach函数”。这失败了,因为类型“转换”失败了,因此:forEachpanic: interface conversion: interface {} is []string, not []interface {}我非常清楚为什么类型“转换”失败,即它不是真正的类型转换,而是一个断言。但是,给定(如果只有我可以迭代)我可以断言每个切片成员,这在原则上应该是可行的。让我们假设我实际上想要一个可以做到这一点的迭代器(而不是一个,等等)。有没有一个好方法可以做到这一点?最好没有反射(虽然我想这没关系),但肯定没有涉及每种类型案例的反射(这是首先具有函数的意义)?forEachforEachStringforEachIntforEach我知道(尚未实现的)泛型提案将在这方面非常有效,但我想用现有的技术来做到这一点!package mainimport (    "fmt")type onEach func(x interface{})func printString(x interface{}) {    xx := x.(string)    fmt.Printf("x is a string '%s'\n", xx)}func printInt(x interface{}) {    xx := x.(int)    fmt.Printf("x is an int '%d'\n", xx)}func forEach(y interface{}, onEach onEach) {    // code to ensure y is a slice omitted    a := y.([]interface{}) // <-------- THIS LINE PANICS    for _, x := range a {        onEach(x)    }}func main() {    s := []string{"foo", "bar"}    i := []int{1, 2, 3}    forEach(s, printString)    forEach(i, printInt)}
查看完整描述

2 回答

?
烙印99

TA贡献1829条经验 获得超13个赞

所以这里有一个使用反射的答案,我想这不会太难看。


package main


import (

    "fmt"

    "reflect"

)


type onEach func(x interface{})


func printString(x interface{}) {

    xx := x.(string)

    fmt.Printf("x is a string '%s'\n", xx)

}


func printInt(x interface{}) {

    xx := x.(int)

    fmt.Printf("x is an int '%d'\n", xx)

}


func forEach(y interface{}, onEach onEach) {

    // code to ensure y is a slice omitted

    v := reflect.ValueOf(y)

    for i := 0; i < v.Len(); i++ {

        onEach(v.Index(i).Interface())

    }

}


func main() {

    s := []string{"foo", "bar"}

    i := []int{1, 2, 3}

    forEach(s, printString)

    forEach(i, printInt)

}


查看完整回答
反对 回复 2022-08-01
?
波斯汪

TA贡献1811条经验 获得超4个赞

使用反射包在任意类型的切片上编写迭代函数:


// forEach calls f for each element of slice s.

// The function f must have a single argument with

// the same type as the slice's element type.

func forEach(s interface{}, f interface{}) {

    sv := reflect.ValueOf(s)

    fv := reflect.ValueOf(f)

    for i := 0; i < sv.Len(); i++ {

        fv.Call([]reflect.Value{sv.Index(i)})

    }

}

像这样使用它:


func printString(s string) {

    fmt.Printf("x is a string %q\n", s)

}


s := []string{"foo", "bar"}

forEach(s, printString)

此答案与问题中的代码和另一个答案不同,因为该函数不需要使用类型评估。f


查看完整回答
反对 回复 2022-08-01
  • 2 回答
  • 0 关注
  • 111 浏览
慕课专栏
更多

添加回答

举报

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