英文:
how to convert a interface{} to its underlying type
问题
我在playground中有一些代码:示例代码
我将一个二维字符串切片传递给一个名为test的函数,该函数可以接受可变参数。在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]))
// 这里会有一个编译错误,因为args[0]的类型现在是interface{},而不是切片,尽管它的底层类型是切片
for i, v := range args[0] {
}
// 那么,当我获取到类型字符串"[][]string"时,如何将args[0]转换为[][]string呢?
// 我知道可以使用类型断言,但是你必须猜测args[0]可能的类型。
// 有没有一种方法可以从类型的字符串表示转换为实际类型?
// 这样我就可以编写这样的代码:
// val := args[0].(reflect.TypeOf(args[0]).String()),这样非常通用
}
func main() {
arr := [][]string{{"asd", "sd", "rt"}, {"34","gf","gf"}}
test(arr)
}
希望对你有所帮助!
英文:
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)
}
答案1
得分: 4
另一种对ANisus答案的变体:
package main
import "fmt"
func main() {
var x interface{} = [][]string{{"Hello"}, {"World", "!"}}
if y, ok := x.([][]string); ok {
fmt.Printf("%v", y)
}
}
另外,可以使用reflect包:
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
英文:
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)
}
答案2
得分: 3
我不完全确定你想要实现什么。
如果你将一个[][]string
作为第一个参数传入,为了遍历它,你必须进行类型断言
或类型切换
:
switch val := args[0].(type) {
case [][]string:
// 在这里处理类型为[][]string的val
}
你可以在Go规范中了解更多关于类型切换的内容:http://golang.org/ref/spec#Switch_statements
如果你尝试将[][]string
切片不变地传递给test
函数:
test(arr...) // 尝试不变地传递切片。
这将失败。这是因为[][]string
不能赋值给[]interface{}
。Go规范中指出:
> 如果最后一个参数可以赋值给切片类型[]T
,并且在参数后面跟着...
,那么它可以不变地作为...T
参数的值传递,此时不会创建新的切片。
英文:
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.
答案3
得分: 1
使用动态值进行类型断言是不可能的,因此 foo.(reflect.TypeOf(bar))
或类似的写法是行不通的。这是因为类型不是一等公民,不能存储在变量中。
你必须明确地写出你希望接口值是哪种类型,要么通过使用类型断言,要么通过使用类型切换。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论