Aerospike golang ListInsertOp multiple values - go

Does the ListInsertOp in golang aerospike client support inserting an array of elements ?
If I use https://godoc.org/github.com/aerospike/aerospike-client-go#ListAppendOp, and pass an array ([]string), it just appends the whole array as one value in the list. Am I using it wrong or is there another way to do the same?

ListAppendOp is a variadic function accepting arbitrary number of arguments of type interface{}. If you call it passing your array, it will receive a slice of interface{} ([]interface{}) with a single element which is your array.
You need to convert your array to a slice of interface{} and expand it using ... when passing it to the function:
a := []string{"a", "b", "c"}
s := make([]interface{}, len(a))
for i, v := range a {
s[i] = v
}
ListAppendOp("bin1", s...)
Example of passing an array to a variadic function:
https://play.golang.org/p/541aJ6dY6D
From the specs:
Passing arguments to ... parameters

Related

Why can I not use an slice of a custom type as an empty interface slice when using append in Go? [duplicate]

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Cannot convert []string to []interface {}
(7 answers)
Cannot use args (type []string) as type []interface {} [duplicate]
(1 answer)
slice of struct != slice of interface it implements?
(6 answers)
Closed 4 months ago.
I'm slightly confused about the behavior of the unpack/spread operator when trying to append into a slice of empty interfaces (i.e. []interface{}) from an slice of a custom type. I expected it to work since the interface{} can hold any type, but I'm currently receiving errors when trying to do this operation.
The following snippet illustrates the issue:
package main
import (
"fmt"
)
type CustomType struct {
value int
}
func main() {
data := []interface{}{}
values := []CustomType{
{value: 0},
{value: 1},
}
// This does not compile:
// data = append(data, values...)
// But this works fine
data = append(data, values[0])
for _, value := range data {
fmt.Printf("Value: %v\n", value)
}
}
Go playground with the snippet above
I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type. When I append the values one by one, then compiler is OK with the operation.
Why is unpacking the values slice not allowed in this situation?
Obviously, the code data = append(data, values...) could be compiled error cannot use values (variable of type []CustomType) as type []interface{} in argument to append
Per faq Can I convert a []T to an []interface{}?
Not directly. It is disallowed by the language specification because the two types do not have the same representation in memory. It is necessary to copy the elements individually to the destination slice. This example converts a slice of int to a slice of interface{}:
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
For your question
I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type.
The difference between the element type CustomType and interface
type CustomType represented in memory like value
type interface{} represented in memory
pointer to type CustomType
value
They have different representations in memory.
Besides that, converting a []CustomType to an []interface{} is O(n) time because each value of the slice must be converted to an interface{}. It could be one complex operation.

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...}

Creating a slice of slice of interfaces in 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{}{}

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