英文:
Unable to assert type `[]string` from `[]interface{}`
问题
我正在尝试处理从mongodb (mgo)检索到的一些数据。
不幸的是,我无法确定字符串列表的正确类型。
我正在处理的函数如下所示:
func generate_version_histogram(userStats []interface{}) map[string]int {
var histogram map[string]int
for _, _u := range userStats {
u := _u.(bson.M)
for _, version := range (u["v"]).([]string) {
if _, alreadyhere := histogram[version]; alreadyhere {
histogram[version] += 1
} else {
histogram[version] = 1
}
}
}
return histogram
}
不幸的是,我遇到了以下运行时错误:
interface conversion: interface is []interface {}, not []string
你知道为什么会发生这种情况吗?我该如何检索这些字符串?
英文:
I am trying to process some data retrieved from mongodb (mgo).
Unfortunately I am unable to assert the correct type for a list of strings.
The function I am working on is the following:
func generate_version_histogram(userStats []interface{}) map[string]int {
var histogram map[string]int
for _, _u := range userStats {
u := _u.(bson.M)
for _, version := range (u["v"]).([]string) {
if _, alreadyhere := histogram[version]; alreadyhere {
histogram[version] += 1
} else {
histogram[version] = 1
}
}
}
return histogram
}
Unfortunately I am getting this following run-time panic:
interface conversion: interface is []interface {}, not []string
Any idea on why this is happening? How can I retrieve those strings?
答案1
得分: 10
这是Go语言中的一个常见错误。
原因如下:在Go中,[]interface{}不是一个接口,而是一个切片类型,其元素都是interface{}类型。
由于每个元素都是interface{}类型,而不是int或Foo等类型,因此每个元素占用的内存更多(interface{}需要存储底层类型和包含的值)。因此,不能直接将[]interface值转换为[]string或[]T值。
那么如何将[]interface{}转换为[]string呢?
解决方案非常简单——逐个转换每个元素。
package main
import "fmt"
func main() {
foo := []interface{}{"a", "b", "c"}
// 我们想将foo转换为[]string
out := []string{}
for _, v := range foo {
// 使用类型断言,将v转换为字符串
out = append(out, v.(string))
}
fmt.Println(out)
}
可运行的示例在这里。
英文:
This is a common mistake with Go.
The reason is as follows: in Go []interface{} is not an interface, it's a slice type, whose elements are each the interface{} type.
Because each element is a interface{}, rather than, say, an int or Foo, more memory is taken up by each element (interface{} needs to store the underlying type, and the value contained). Therefore, it's not possible to directly convert a []interface value into a []string or []T value.
How do you convert []interface{} into []string, then?
The solution is quite simple — you convert each element.
package main
import "fmt"
func main() {
foo := []interface{}{"a", "b", "c"}
// we want to convert foo to a []string
out := []string{}
for _, v := range foo {
// using a type assertion, convert v to a string
out = append(out, v.(string))
}
fmt.Println(out)
}
Runnable example here.
答案2
得分: 4
一个[]interface{}永远不会是一个[]string。切片有一个后备数组,这些元素必须具有一定的大小。根据实现细节的不同,这可能或可能不完全正确,但是[]interface{}的每个元素都包含一个interface{}。如果所有这些interface{}都是“真正的”字符串,它们不会是字符串本身,而是字符串的包装器或指向它的指针。因此,您必须自己转换[]interface{}的每个单独元素。
stringSlice := make([]string, len(u["v"]))
for i, raw := range u["v"] {
str, ok := raw.(string)
if !ok {
// 出现问题,不是我们期望的字符串
}
stringSlice[i] = str
}
英文:
A []interface{} will never be a []string. A slice has a backing array, and those elements have to be of a certain size. This may or may not be exactly correct depending on implementation details, but each element of an []interface{} will contain an interface{}. If all of these interface{} are "really" strings, they won't be the strings themselves but rather a wrapper over the string or a pointer to it. Thus you have to convert each individual element of a []interface{} yourself.
stringSlice := make([]string, len(u["v"]))
for i,raw := range u["v"] {
str,ok := raw.(string)
if !ok {
// Something is wrong, not a string like we expected
}
stringSlice[i] = str
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论