My input is an interface{}, and I know it can be an array of any type.
I'd like to read one of the elements of my input, so I try to convert my interface{} into an []interface{}, but go will give me the following error:
panic: interface conversion: interface {} is []map[string]int, not []interface {}
How can I do that conversion? (without reflect if possible).
Playground test
Thanks
The solution involving the reflect package.
package main
import (
"fmt"
"reflect"
)
func main() {
var v interface{} = []string{"a", "b", "c"}
var out []interface{}
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Slice {
for i := 0; i < rv.Len(); i++ {
out = append(out, rv.Index(i).Interface())
}
}
fmt.Println(out)
}
// Output:
// [a b c]
I'm actually working on this right now as my issue involves taking something from a json object (map[string]interface{}) which may or may not contain a particular key ({"someKey": [a, b, c, ...]) and if it does contain that key then we want to take that (which will necessarily be interface{} type) and convert it to []interface{}. The method I've found so far is to use json marshall/unmarshall. This seems a little hacky to me, will update if I find a more elegant solution. Til then, you can have my method:
https://play.golang.org/p/4VAwQQE4O0b
type a map[string]interface{}
type b []string
func main() {
obj := a{
"someKey": b{"a", "b", "c"},
}
if obj["someKey"] != nil { // check the value exists
var someArr []interface{}
//marshal interface to byte and then unmarshal to []interface{}
somebytes, _ := json.Marshal(obj["someKey"])
err := json.Unmarshal(somebytes, &someArr)
if err != nil {
fmt.Println("Error in unmarshal")
}
fmt.Println(someArr)
}
}
How can I do that conversion? (without reflect if possible).
Please consider type switches.
Reflection is expensive.
func toSlice(i interface{}) []interface{} {
var out []interface{}
switch v := i.(type) {
case []interface{}:
for x := 0; x < len(v); x++ {
out = append(out, v[x])
}
default:
fmt.Printf("invalid type: %T\n", v)
}
return out
}
The point of the interface is to define the behaviour you want to use, if you use an empty interface, you know nothing about the types in that slice.
If you want to print it, you can use println or printf with no conversion.
If you want to access it, and must allow any type, you can use reflect (slow and complex to use).
If you want to acess it, and use common behaviour/ data that you can define functions for, define an interface, e.g. :
type Doer interface {
Do() error
}
parentStruct := []Doer{...}
testStruct.Do()
If none of that works, wait for Go 2 and generics.
For anyone finding this in 2022, now that we have generics you can do it like this:
func convertSlice[T any](data []T) []interface{} {
output := make([]interface{}, len(data))
for idx, item := range data {
output[idx] = item
}
return output
}
I think what you are looking is type assertion
package main
import (
"fmt"
)
func main() {
parentStruct := map[string]interface{}{
"test": []map[string]int{
{"a": 1, "b": 2},
{"c": 3},
},
}
testStruct := parentStruct["test"].([]map[string]int)
fmt.Println(testStruct)
}
read this link: https://golang.org/ref/spec#Type_assertions
https://play.golang.org/p/81uL2hgrN3l
Related
func main() {
strSlice := []string{"a", "b", "c"}
f(strSlice)
}
func f(slice interface{}) {
anySlice, isSlice := slice.([]interface{})
fmt.Printf("isSlice = %t, anySlice = %#v\n", isSlice, anySlice)
}
Playground: https://play.golang.org/p/UN25mIOqmOd
This program prints isSlice = false, anySlice = []interface {}(nil). Why is that?
I would have expected this type asssertion to be possible.
And: Is there a way to dynamically check that interface{} is a slice of something?
The type assertion fails because a []string is not an []interface{}. See the FAQ for details.
Use the reflect package to determine if the concrete value in an interface is a slice:
func f(slice interface{}) {
isSlice := reflect.ValueOf(slice).Kind() == reflect.Slice
fmt.Printf("isSlice = %t, anySlice = %#v\n", isSlice, slice)
}
Run it on the playground.
You can also use the reflect package to iterate through the values:
v := reflect.ValueOf(slice)
isSlice := v.Kind() == reflect.Slice
if isSlice {
for i := 0; i < v.Len(); i++ {
fmt.Printf("%d: %v\n", i, v.Index(i).Interface())
}
}
Run it on the playground.
This program prints isSlice = false, anySlice = []interface {}(nil). Why is that?
because slice doesn't contain a []interface{}, it contains a []string. Those are different types, and Go doesn't give you any notion of covariant container types.
And: Is there a way to dynamically check that interface{} is a slice of something?
Yes, you can use reflection:
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")
}
}
Actually doing anything with that information may be more involved.
Notice that if you change your assertion to: slice.([]string) things will work as expected. This makes sense when you consider how Go handles string to interface{} type assertions. The following will result in a compilation error:
package main
func main() {
s := "some string"
i := s.(interface{})
}
Error:
invalid type assertion: s.(<inter>) (non-interface type string on left)
It makes sense that going from []string to []interface{} should also fail since Go does not treat strings as interface{} types.
I am new to Go & I am trying to learn how to cast interface{} to a Map. Here is an example of what I am trying to implement.
Playground link : https://play.golang.org/p/3jhKlGKO46Z
Thanks for the help.
package main
import (
"fmt"
)
func main() {
Map := make(map[string]interface{})
test(Map)
for k,v := range Map {
fmt.Println("key : %v Value : %v", k, v)
}
}
func test(v interface{}) error{
data := make(map[int]interface{})
for i := 0; i < 10; i++ {
data[i] = i * 5
}
for key,val := range data {
// fmt.Println("key : %v Value : %v", key, val)
v[key] = val
}
return nil
Go supports type assertions for the interfaces. It provides the concrete value present in the interface.
You can achieve this with following code.
m, ok := v.(map[int]interface{})
if ok {
// use m
_ = m
}
If the asserted value is not of given type, ok will be false
If you avoid second return value, the program will panic for wrong assertions.
I strongly recommend you to go through https://tour.golang.org
Can someone explain why this doesn't work and how can we return slices of interfaces, []interface{}, from functions like showed in the example?
import (
"fmt"
)
func main() {
var test []string
Test(&test)
fmt.Println(test)
}
func Test(t interface{}) {
a := []interface{}{"first", "second"}
fmt.Println(a)
t = a
}
Example of running code can be found here:
https://play.golang.org/p/vcEGHSdWrjv
BTW, this is the func I'm trying to extract data from: https://godoc.org/github.com/mongodb/mongo-go-driver/mongo#Collection.Distinct
Note: the type we expect is not always of type []string, I'm just using string as an example here.
Thanks!
In you example, you are not trying to "return" a slice but rather you seem to be looking to modify the argument to point to a new slice of strings.
The way you are doing it does not work cause in Go, arguments are passed by value.
When you do this:
t = a
t is a copy of the &test you are sending to the function as an argument.
So modifying t does not change your test variable.
You need to pass in the address of a pointer in order to be able to modify what the pointer points to.
Try this way:
func main() {
var test *[]string
Test(&test)
fmt.Println(*test)
}
func Test(t interface{}) {
a := []string{"first", "second"}
fmt.Println(a)
*t.(**[]string) = &a
}
Output:
[first second]
[first second]
Playground: https://play.golang.org/p/tliMrmliykp
Because an []string and a []interface{} are different types, you cannot assign one to the other.
You must copy the slice to convert []interface{} to a slice of some specific type. If you know that the []interface{} always contains string values, then use the following:
func stringSlice() []string {
a := []interface{}{"first", "second"} // query result
fmt.Println(a)
result := make([]string, len(a))
for i := range a {
var ok bool
result[i], ok = a[i].(string)
if !ok {
// handle error with unexpected type
}
}
return result
}
If the result can have arbitrary element types, then use reflection to copy the slice:
func anySlice(result interface{}) {
a := []interface{}{"first", "second"} // query result
slice := reflect.ValueOf(result).Elem()
elementType := slice.Type().Elem()
for _, v := range a {
rv := reflect.ValueOf(v)
if !rv.Type().AssignableTo(elementType) {
// handle error with unexpected type
}
slice.Set(reflect.Append(slice, rv))
}
}
Use it like this:
var s []string
anySlice(&s)
playground example
I'm parsing a JSON object which contains an array of strings :
var ii interface{}
json := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
err := json.Unmarshal([]byte(json), &ii)
if err != nil {
log.Fatal(err)
}
data := ii.(map[string]interface{})
fmt.Println(data["aString"]) // outputs: ["aaa_111" "bbb_222"]
I tried to convert data["aString"] to []string to be able to loop over it, but it fails :
test := []string(data["aString"]).([]string)
fmt.Println(test) // panic -> interface conversion:
// interface is string, not []string
How can I convert data["aString"] ?
edit:
I didn't express myself properly. If I print data, I have such map :
map[aString:["BBB-222","AAA-111"] whatever:ccc]
I want to loop over aString (to manipule each array entry). But I can't find how, because aString is type interface {} :
for i, v := range aString { // <-- fails
// ...
fmt.Println(i, v)
}
That's why I want to convert aString. I don't want to convert a string which looks like an array to an array.
I recommend you move away from this implementation in general. Your json may vary but you can easily use objects and avoid all this type unsafe nonsense.
Anyway, that conversion doesn't work because the types inside the slice are not string, they're also interface{}. You have to iterate the collection then do a type assertion on each item like so:
aInterface := data["aString"].([]interface{})
aString := make([]string, len(aInterface))
for i, v := range aInterface {
aString[i] = v.(string)
}
Is it what you need?
package main
import (
"fmt"
"encoding/json"
)
func main() {
js := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
a := make(map[string]interface{})
json.Unmarshal([]byte(js), &a)
for _, v := range a["aString"].([]interface{}) {
str := v.(string)
fmt.Println(str)
}
}
Check on Go Playground
For another approach, you can use a struct instead:
package main
import (
"encoding/json"
"fmt"
)
func main() {
s := []byte(`{"aString": ["aaa_111", "bbb_222"], "whatever":"ccc"}`)
var t struct {
Astring []string
Whatever string
}
json.Unmarshal(s, &t)
fmt.Printf("%+v\n", t) // {Astring:[aaa_111 bbb_222] Whatever:ccc}
}
I am a Go beginner, coming from Ruby land.
In Ruby, you could do something like this.
Time.send("now") is equivalent to Time.now, as you are sending the message now to the object Time
Is there something similar in golang?
There is no built in way of calling an arbitrary function from a string in Go.
You can create something similar by registering functions to a map[string].
A working example:
package main
import "fmt"
var m = map[string]func(){
"now": func() { fmt.Println("The time is now") },
"then": func() { fmt.Println("Once upon a time") },
}
func main() {
cmd := "then"
m[cmd]()
}
play.golang.org
There is also the possibility of using reflection in order to call a method by name. You can look at the reflect package for MethodByName and Call. You can also check this Stackoverflow question.
As other suggested, you can do it yourself by mapping strings to functions, but the strong-typing nature of Go makes it difficult to translate .send directly into Go.
You can still use reflection if you really need to access a field or method by name:
import "reflect"
import "fmt"
type A struct {
Number int
}
func (a *A) Method(i int) int {
return a.Number + i;
}
func main() {
a := &A{Number: 1}
// Direct access
fmt.Printf("Direct -> Nb: %d, Nb + 2: %d\n", a.Number, a.Method(2));
v := reflect.ValueOf(*a)
vp := reflect.ValueOf(a)
field := v.FieldByName("Number")
meth := vp.MethodByName("Method")
args := []reflect.Value{reflect.ValueOf(2)}
// Reflection access
fmt.Printf("Reflect -> Nb: %d, Nb + 2: %d\n",
field.Interface().(int),
meth.Call(args)[0].Interface().(int))
}
Outputs:
Direct -> Nb: 1, Nb + 2: 3
Reflect -> Nb: 1, Nb + 2: 3
play.golang.org
Note however:
How cumbersome that is. Usually, performing a map as suggested by #ANisus is a more idiomatic way of doing
You still have to perform your conversions in the end.
Using the reflect packages changes your typed variable into more flexible Value objects, but these are very cumbersome to use in practice. It is usually better if you can find a way to express your intent without relying on reflection.
Also note that here, we had to use two Values, one for a (a pointer to A) for the method, and one for *a (a A structure) for the field. Trying to get a method defined with a pointer receiver with a non-pointer Value (or conversely, trying to obtain a field via a pointer Value) will result in a panic. More generally, due to the dynamic nature of reflected Values and its difference with the usual typed Go, expect a lot of convenience features (such as automatic referencing/dereferencing) to be absent on Values.
Also, expect quite a bit of runtime panics while debugging, as it is the only way for dynamic Value calls to fail !
Reference: the reflect package
No. Work your way through http://tour.golang.org/ and http://golang.org/doc/effective_go.html and you will have a proper understanding of how method invocation works.
Here is a working example using reflect
package main
import (
"fmt"
"os"
"reflect"
)
// Send sends a message to(calls a method of) obj, with args.
// The return value of the method call is set to ret and any error to err.
func Send(obj interface{}, method string, args ...interface{}) (ret []reflect.Value, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
objValue := reflect.ValueOf(obj)
argsValue := make([]reflect.Value, 0, len(args))
for _, arg := range args {
argsValue = append(argsValue, reflect.ValueOf(arg))
}
mtd := objValue.MethodByName(method)
if !mtd.IsValid() {
return nil, fmt.Errorf("%v does not have a method %v", reflect.TypeOf(obj), method)
}
ret = mtd.Call(argsValue)
return
}
// Then do some tests.
type A struct {
value int
}
func (a A) Value() int {
return a.value
}
func (a *A) SetValue(v int) {
a.value = v
}
func main() {
var (
ret []reflect.Value
err error
)
// StdOut.WriteString("Hello, World!\n")
_, err = Send(os.Stdout, "WriteString", "Hello, World!\n")
handleError(err)
var a = &A{100}
// ret = a.Value()
ret, err = Send(a, "Value")
handleError(err)
fmt.Printf("Return value is: %v\n", ret[0].Int())
// a.SetValue(200)
_, err = Send(a, "SetValue", 200)
handleError(err)
// ret = a.Value()
ret, err = Send(a, "Value")
handleError(err)
fmt.Printf("Return value is: %v", ret[0].Int())
}
func handleError(err error) {
if err != nil {
panic(err)
}
}
I based my code on this description of send.
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
http://play.golang.org/p/lXlzBf_fGZ
package main
import "strings"
type Klass struct{}
func (k Klass) Hello(args ...string) string {
return "Hello " + strings.Join(args, " ")
}
func (k Klass) Send(symbol func(Klass, ...string) string, args ...string) string {
return symbol(k, args...)
}
func main() {
k := new(Klass)
k.Send(Klass.Hello, "gentle", "readers") //=> "Hello gentle readers"
}
The big difference between the two is that Go's Send function is only implemented for Klass and only works on methods that take a variable number of strings as parameters and return a single string. This is because Go is a statically typed language where Ruby is dynamically typed. Go does support dynamic typing via the reflect library, but it is an unpleasant experience and not the way general Go code is meant to be written.