1

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
  • 1
    Try asserting each member of the slice instead of the entire slice. Commented May 10, 2014 at 14:05

2 Answers 2

10

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.