Creating a slice of slice of interfaces in go - go

I'm trying to create a function that returns the all the key, value of a map as a slice of slice of tuples (where each tuple is {key, value})
Here's the code:
func ReturnTuples(map_ map[interface{}]interface{}) [][]interface{} {
toReturn := []([]interface{})
...
But I'm getting error for the toReturn line:
type [][]interface {} is not an expression
How should I declare a slice of slice of interfaces? I see this as the only way. I tried without parenthesis like:
[][]interface{}
but it won't work either.
I tried to search for 'golang slice of slice' on google but very few things appear. For example I've only found how to create a simple one made of uint8, which is: [][]uint8.

The element type of the slice is interface{}, so a composite literal needs an additional pair of braces: []interface{}{}.
In case of slice of slices:
toReturn := [][]interface{}{}
Or when using make(), you specify a type (and not a composite literal):
toReturn := make([][]interface{}, 0, len(map_))

You're creating an instance, not defining a type, so you need an extra pair of curly braces to initialize the variable:
toReturn := [][]interface{}{}

Related

"non-interface type map[string]interface {} on left" error

I have a struct:
type ListsObj struct {
Page string `json:"pages"`
Count string `json:"count"`
Lists []map[string]interface{} `json:"assets"`
}
I am trying to do something like below:
lists := a.Lists
for _, list:= range lists{
listData := list.(map[string]interface {})
}
a is of type ListsObj struct.
I am getting following error:
invalid type assertion: list.(map[string]) (non-interface type
map[string]interface {} on left)
EDIT:
What I actually need to do is to call a function:
func WriteMapper(a interface {}) interface{} {
}
lists := a.Lists
for _, list:= range lists{
list = WriteMapper(list)
}
but this gives another error:
cannot use WriteMapper(list) (type interface {}) as type
map[string]interface {} in assignment: needs type assertion
EDIT: I think I got it... the function returns interface and I am trying to assign that to map[string]interface {}??
In your code, a.Lists (and therefore also lists) is a []map[string]interface{}, a slice of maps. You're then iterating over that slice, and assigning the value on each iteration to the variable list (which is kinda oddly named, as it's holding a map, but that's a separate concern).
Now, list is of type map[string]interface{}. There's no need for you to type-assert it into that, since it's already that type!
To use list as the map[string]interface{} that it is, you just use it:
for _, list := range lists {
someValue := list["some-key"]
fmt.Println(someValue)
}
If you're trying to do something different that just using the map, I'd ask that you please clarify.

Generic function which appends two arrays

Not able to figure out how to convert interface{} returned from function into an array of structs
As part of some practise i was trying to create a function which can take 2 slices of some type and concatenates both and returns the slice.
The code can be found here - https://play.golang.org/p/P9pfrf_qTS1
type mystruct struct {
name string
value string
}
func appendarr(array1 interface{}, array2 interface{}) interface{} {
p := reflect.ValueOf(array1)
q := reflect.ValueOf(array2)
r := reflect.AppendSlice(p, q)
return reflect.ValueOf(r).Interface()
}
func main() {
fmt.Println("=======")
array1 := []mystruct{
mystruct{"a1n1", "a1v1"},
mystruct{"a1n2", "a1v2"},
}
array2 := []mystruct{
mystruct{"a2n1", "a2v1"},
mystruct{"a2n2", "a2v2"},
}
arrayOp := appendarr(array1, array2)
fmt.Printf("arr: %#v\n", arrayOp) // this shows all the elements from array1 and 2
val := reflect.ValueOf(arrayOp)
fmt.Println(val) // output is <[]main.mystruct Value>
fmt.Println(val.Interface().([]mystruct)) // exception - interface {} is reflect.Value, not []main.mystruct
}
I may have slices of different types of structs. I want to concatenate them and access the elements individually.
If there is any other way of achieving the same, please do let me know.
reflect.Append() returns a value of type reflect.Value, so you don't have to (you shouldn't) pass that to reflect.ValueOf().
So simply change the return statement to:
return r.Interface()
With this it works and outputs (try it on the Go Playground):
=======
arr: []main.mystruct{main.mystruct{name:"a1n1", value:"a1v1"}, main.mystruct{name:"a1n2", value:"a1v2"}, main.mystruct{name:"a2n1", value:"a2v1"}, main.mystruct{name:"a2n2", value:"a2v2"}}
[{a1n1 a1v1} {a1n2 a1v2} {a2n1 a2v1} {a2n2 a2v2}]
[{a1n1 a1v1} {a1n2 a1v2} {a2n1 a2v1} {a2n2 a2v2}]
You also don't need to do any reflection-kungfu on the result: it's your slice wrapped in interface{}. Wrapping it in reflect.Value and calling Value.Interface() on it is just a redundant cycle. You may simply do:
arrayOp.([]mystruct)
On a side note: you shouldn't create a "generic" append() function that uses reflection under the hood, as this functionality is available as a built-in function append(). The builtin function is generic, it gets help from the compiler so it provides the generic nature at compile-time. Whatever you come up with using reflection will be slower.

How to add more data into struct with append or without append?

Well we can use Golang built in append method to add more data into a defined struct. e.g.
type aclStruct struct { acl string}
a := []aclStruct{aclStruct{"A"}, aclStruct{"B"}}
a = append(a, aclStruct{"C"})
No Doubt it's working. But when I tried without append method it's producing an error. E.g.
What I am trying to do is :
a := append(aclStruct{"A"}, aclStruct{"B"}, aclStruct{"C"})
Even not sure sure it's a right way for struct because on array it's works fine. Also is there any way of doing this without using of append ?
Any Help??
Even not sure sure it's a right way for struct because on array it's works fine.
The append function appends elements to the end of a slice.
structs are declared statically. There is simply no way in Go to change their structure to add fields to them at runtime.
If you want a slice of structs, which you may use to track multiple representations of the struct, perhaps with different data points, you can build that structure in several ways:
Using append, ensuring the first argument passed is a (possibly empty) slice:
a := append([]aclStruct{}, aclStruct{"A"}, ...)
Declare the slice variable a and pass this to append:
var a []aclStruct{}
a = append(a, aclStruct{"A"}, ...)
Declaring and initializing the slice with values inline:
a := []aclStruct{{"A"}, {"B"}}
Note that you don't need to re-specify the concrete type for each slice element, as it can be inferred from the type of the slice)
If you want to declare slice of three elements use:
a := []aclStruct{aclStruct{"A"}, aclStruct{"B"}, aclStruct{"C"}}
append should be used to modify currently existing slice (it appends to a slice). It is throwing an error, because first argument should be a slice.
if you want to use it:
var a []aclStruct
append(a, aclStruct{"A"})
GoDoc answers the question well:
func append(slice []Type, elems ...Type) []Type
The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice. It is therefore necessary to store the result of append, often in the variable holding the slice itself:
slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)
first argument of append must be a slice so correct way of doing it is:
a := append([]aclStruct{aclStruct{"A"}}, aclStruct{"B"}, aclStruct{"C"})
or
append([]aclStruct{{"A"}}, aclStruct{"B"}, aclStruct{"C"})
a way of doing it without append is:
a := []aclStruct{aclStruct{"A"}, aclStruct{"B"}}
appendedArray := []aclStruct{aclStruct{"C"}, a...}

Appending concrete values to array of interfaces

I have the following structures:
type Type interface {
getFoo() []byte
}
type Concrete struct {
}
func (this *Concrete) getFoo() []byte {
example := []byte{2, 3, 4}
return example
}
Now I have some array of Type interfaces, e.g.:
var arr []*Type
And I want to create array of concrete structures and initialize the above array with it, e.g.:
var cObjArr []*Concrete
cObj := new(Concrete)
cObjArr = append(cObjArr, cObj)
arr = cObj
But it gives me an error that cannot use type []*Concrete as type []*Type in assignment. What's wrong?
There are a few problems here.
First,
type Type interface{} {
getFoo() []byte
}
should be
type Type interface {
getFoo() []byte
}
I assume that is a result of trying to show a small, reproducible example.
The next is that arr should be a slice of type Type, not *Type. A pointer to an interface is VERY rarely what you actually mean.
So, your arr is now a slice of Type... []Type. For the remainder of the current scope arr will always HAVE TO BE of type []Type.
cObjArr is of type []*Concrete. That's fine, but the value of cObjArr can not be assigned to arr since it is a different type.
You have a couple options here.
Instead of appending to cObjArr, just append to arr
https://play.golang.org/p/m3-83s6R5c
Or iterate through cObjArr and append to arr
https://play.golang.org/p/wvWaChcOWY
First of all, you should declare arr as []Type instead of []*Type. The objects you want to put in the array are Type, not *Type (*Concrete implements the Type interface).
Based on the error, your code must be trying to do arr = cObjArr. You can't do that because the types of the two slice objects are different. Instead, you can append cObj directly to arr.

How can I call len() on an interface?

I'm writing a test that a JSON list is empty.
{"matches": []}
The object has type map[string]interface{}, and I want to test that the list is empty.
var matches := response["matches"]
if len(matches) != 0 {
t.Errorf("Non-empty match list!")
}
However I'm told at compile time that this is invalid
invalid argument matches (type interface {}) for len
If I try casting to a list type:
matches := response["matches"].([]string)
I get a panic:
panic: interface conversion: interface is []interface {}, not []string [recovered]
What do I want to write here?
JSON parsing with maps in Go uses interfaces everywhere. Imagine you have the following JSON object:
{
"stuff" : [
"stuff1",
"stuff2",
"stuff3",
]
}
The Go JSON library will parse the outer object as a map from keys to values, as you've seen in your code. It maps variable names as keys to the values that correspond to those variable names. However, since it has no way of knowing ahead of time what those values are, the value type of the map is simply interface{}. So let's say you know there's a key called "stuff", and you know that its value is an array. You could do:
arr := myMap["stuff"]
And you know that it's an array type, so you can actually instead do:
arr := myMap["stuff"].([]interface{})
the problem here is that while you're right that it's an array, and the JSON library knows this, it has no way of knowing that every element will be of type string, so there's no way for it to decide that the array type should actually be []string. Imagine if you had done this instead:
{
"stuff" : [
"stuff1",
"stuff2",
3
]
}
Well "stuff" can't now be an array of strings because one of the elements isn't a string. In fact, it can't be an array of anything - there's no single type that would satisfy the types of all of the elements. So that's why the Go JSON library has no choice but to leave it as []interface{}. Luckily, since all you want is the length, you're already done. You can just do:
arr := myMap["stuff"].([]interface{})
l := len(arr)
Now that's all fine and good, but let's say that down the road you want to actually look at one of the elements. You could now take out an element and, knowing that it's a string, do:
arr := myMap["stuff"].([]interface{})
iv := arr[0] // interface value
sv := iv.(string) // string value
NOTE
When I say "array," I mean array in the JSON sense - these are JSON arrays. The data structure that represents them in Go is called a "slice" (Go has arrays too, but they're a separate thing - if you're used to arrays in languages like C or Java, Go slices are the closest analogue).
When dealing with JSON, you can add type declarations for array and object, then add methods as needed to help with conversion:
package main
import "encoding/json"
type (
array []interface{}
object map[string]interface{}
)
func (o object) a(s string) array {
return o[s].([]interface{})
}
func main() {
data := []byte(`{"matches": []}`)
var response object
json.Unmarshal(data, &response)
matches := response.a("matches")
mLen := len(matches)
println(mLen == 0)
}
https://golang.org/ref/spec#Type_declarations

Resources