Reputation: 1581
I have some code in the playground: sample code
I pass a two dimension string slice into a function test, which can accept variadic arguments, and in test() I can get the first argument's underlying type, but how can I convert it back to its underlying type? because I have to iterate on its underlying type
I don't like to hard code it like:
if reflect.TypeOf(args[0]).String() == "[][]string" {
val := args[0].([][]string)
}
the question is if I know its type string is "[][]string" or something else, how can I convert it to the type?
I post the full code here, and add some comments:
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)
}
Upvotes: 2
Views: 2934
Reputation: 52151
Another variation on ANisus answer :
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
Otherwise, use the reflect package :
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
Upvotes: 4
Reputation: 57737
It is not possible to use a dynamic value for a type assertion, so
foo.(reflect.TypeOf(bar))
or something similar will not work. This is because types are not first class citizens and can't be stored in a variable.
You always have to write explictly which type you want the interface value to be, either by using a type assertion or a type switch.
Upvotes: 1
Reputation: 78065
I am not entirely sure what you wish to achieve.
If you pass in a [][]string
as the first argument, in order to iterate over it, you must do a type assertion
or type switch
:
switch val := args[0].(type) {
case [][]string:
// Do what you want with val which is of type [][]string
}
You can read more about type switches in the Go specifications: http://golang.org/ref/spec#Switch_statements
If you try to pass the [][]string slice unchanged to test
:
test(arr...) // Attempt to pass the array unchanged.
this will fail. This is due to [][]string not being assignable to []interface{}. The Go specification states:
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
Upvotes: 3