如何将接口{}转换为其基础类型

时间:2014-01-23 13:38:33

标签: reflection interface go slice

我在操场上有一些代码:sample code

我将一个二维字符串切片传递给一个函数测试,它可以接受可变参数,在test()中我可以得到第一个参数的底层类型,但是如何将它转换回它的底层类型呢?因为我必须迭代它的基础类型

我不喜欢硬编码:

if reflect.TypeOf(args[0]).String() == "[][]string" {
    val := args[0].([][]string)
}

问题是,如果我知道它的类型字符串是“[] [] string”或其他东西,我该如何将其转换为类型?

我在这里发布完整代码,并添加一些评论:

package main

import (
    "reflect"
    "fmt"
)

func test(args ...interface{}) {
    fmt.Println("type", reflect.TypeOf(args[0]))
    // here will be a compile error, because args[0]'type now is interface{}, 
    // not a slice, though it's underlying type is slice

    for i, v := range args[0] {    

    }

    // so, how could I convert args[0] to [][]string when I get its type 
    // string "[][]string" ?
    // I know use type assertion is possible, but you must guess the possible 
    // type the args[0] will be.
    // is there a way to do it from a type's string representation to the 
    // actual type?
    // so I can write code like this: 
    // val := args[0].(reflect.TypeOf(args[0]).String()), which is very general


}
func main() {
    arr := [][]string{{"asd", "sd", "rt"}, {"34","gf","gf"}}
    test(arr)
}

3 个答案:

答案 0 :(得分:3)

我不完全确定你想要达到的目标。

如果您传递[][]string作为第一个参数,为了迭代它,您必须执行type assertiontype switch

switch val := args[0].(type) {
case [][]string:
    // Do what you want with val which is of type [][]string
}

您可以在Go规范中详细了解类型开关:http://golang.org/ref/spec#Switch_statements

如果您尝试将[] []字符串切片保持不变为test

test(arr...) // Attempt to  pass the array unchanged.

这会失败。这是由于[] []字符串无法分配给[] interface {}。 Go规范声明:

  

如果最终参数可分配给切片类型[] T,则可能是   如果参数是,则传递未更改为... T参数的值   后跟....在这种情况下,不会创建新切片。

答案 1 :(得分:3)

ANisus的另一个变体回答:

package main

import "fmt"

func main() {
    var x interface{} = [][]string{{"Hello"}, {"World", "!"}}

    if y, ok := x.([][]string); ok {
        fmt.Printf("%v", y)
    }
}

http://play.golang.org/p/tGYbhzuUnr


否则,请使用反射包:

import (
    "fmt"
    "reflect"
)

func process(i interface{}) {
    fmt.Printf("Processing %v\n", i)

    if reflect.TypeOf(i).Kind() == reflect.Slice {
        v := reflect.ValueOf(i)
        for i := 0; i < v.Len(); i++ {
            process(v.Index(i).Interface())
        }
    }
}

func main() {
var x = [][]string{{"Hello"}, {"World", "!"}}
var y = []int{2,3,5,7,9}
var z = 'H'

process(x)
process(y)
process(z)
}

http://play.golang.org/p/MAqIgxzLuC

答案 2 :(得分:1)

不能对类型断言使用动态值,所以

foo.(reflect.TypeOf(bar))

或类似的东西不起作用。这是因为类型不是一等公民 并且不能存储在变量中。

你总是要明确地写出你想要接口值的类型 通过使用类型断言或类型开关。