func main() {
strSlice := []string{"a", "b", "c"}
f(strSlice)
}
func f(slice interface{}) {
anySlice, isSlice := slice.([]interface{})
fmt.Printf("isSlice = %t, anySlice = %#vn", isSlice, anySlice)
}
游乐场:https://play.golang.org/p/UN25mIOqmOd
该程序打印isSlice = false, anySlice = []interface {}(nil)
.为什么? 我本来希望这种类型的断言是可能的。
并且:有没有办法动态检查接口{}是某物的一部分?
类型断言失败,因为[]string
不是[]interface{}
。有关详细信息,请参阅常见问题解答。
使用反射包确定接口中的具体值是否为切片:
func f(slice interface{}) {
isSlice := reflect.ValueOf(slice).Kind() == reflect.Slice
fmt.Printf("isSlice = %t, anySlice = %#vn", isSlice, slice)
}
在操场上运行它。
还可以使用反射包循环访问值:
v := reflect.ValueOf(slice)
isSlice := v.Kind() == reflect.Slice
if isSlice {
for i := 0; i < v.Len(); i++ {
fmt.Printf("%d: %vn", i, v.Index(i).Interface())
}
}
在操场上运行它。
此程序打印
isSlice = false, anySlice = []interface {}(nil)
。为什么?
因为slice
不包含[]interface{}
,所以它包含一个[]string
。这些是不同的类型,Go 没有给你任何协变容器类型的概念。
并且:有没有办法动态检查接口{}是某物的一部分?
是的,您可以使用反射:
func f(slice interface{}) {
typ := reflect.TypeOf(slice)
if typ.Kind() == reflect.Slice {
elemType := typ.Elem()
fmt.Println("slice of", elemType.Name())
} else {
fmt.Println("not a slice")
}
}
实际上,对这些信息做任何事情可能会更复杂。
请注意,如果您将断言更改为:slice.([]string)
事情将按预期工作。当你考虑 Go 如何处理string
到interface{}
类型断言时,这是有意义的。以下情况将导致编译错误:
package main
func main() {
s := "some string"
i := s.(interface{})
}
错误:
invalid type assertion: s.(<inter>) (non-interface type string on left)
从[]string
到[]interface{}
也应该失败是有道理的,因为 Go 不会将字符串视为interface{}
类型。