How to convert []*Cookie to []Cookie in Golang - go

I have a []*Cookie array, but how to get []Cookie array? I tried to use the * symbol but there was a syntax error.

Go does not provide an automatic conversion from slice of pointers to values to a slice of values.
Write a loop to do the conversion:
result := make([]Cookie, len(source))
for i := range result {
result[i] = *source[i]
}

Related

go reflect: how to dynamically create a pointer to a pointer to ...?

I would like to create a reflect.Value that represents a multiple-level nested pointer to a final value. The nesting level is not known at compile time. How can I create pointers to pointers using reflect?
I already stumble at the "unaddressable value" hurdle when trying to create a pointer to a pointer.
dave := "It's full of stars!"
stargazer := reflect.ValueOf(&dave)
stargazer = stargazer.Addr() // panic: reflect.Value.Addr of unaddressable value
Same for stargazer.UnsafeAddr(), etc. While stargazer.Elem().UnsafeAddr() etc. works, I can't see how this helps in (recursively) creating a new non-zero pointer to a pointer...
Use the following code to create a pointer to the value in stargazer.
p := reflect.New(stargazer.Type())
p.Elem().Set(stargazer)
// p.Interface() is a pointer to the value stargazer.Interface()
Example:
dave := "It's full of stars!"
stargazer := reflect.ValueOf(dave)
for i := 0; i < 10; i++ {
p := reflect.New(stargazer.Type())
p.Elem().Set(stargazer)
stargazer = p
}
fmt.Printf("%T\n", stargazer.Interface()) // prints **********string

Duplicate slice of pointers to structs with slightly different values

Given two nested types
type Inner struct {
InnerVal int
}
type Outer struct {
InnerStruct *Inner
OuterVal int
}
I need to duplicate a slice of pointers to Outer
originalSlice := []*Outer{<plenty_of_items>}
with itself, but having updated field values in the duplicates, including the Outer.InnerStruct.InnerVal.
To do so I create a new slice of the same type and length as originalSlice, append pointers to newly created structs with altered values to it, and finally append these items to the originalSlice
duplicateSlice := make([]*Outer, len(originalSlice))
for _, originalItem := range originalSlice {
duplicateSlice = append(duplicateSlice, &Outer{
InnerStruct: &Inner{
InnerVal: originalItem.InnerStruct.InnerVal + 1
},
OuterVal: originalItem.OuterVal + 1,
})
}
originalSlice = append(originalSlice, duplicateSlice...)
While this is verbose enough to follow the pointers around, or so I thought, when passed to a function right after as nowDoubledSlice, and accessed via loop
someOtherSlice := make([]*types.Inner, len(nowDoubledSlice))
for i, doubledItem := range nowDoubledSlice {
someOtherSlice[i] = doubledItem.InnerStruct
}
I get a
runtime error: invalid memory address or nil pointer dereference
Why is that? And is there a more elegant or idiomatic way to duplicate a slice of pointers to structs, while altering the duplicates' fields?
It's nothing to do with your pointer creation, it's your slice allocation. This line:
duplicateSlice := make([]*Outer, len(originalSlice))
Creates a new slice of length len(originalSlice), filled with zero-value elements. What you likely want instead is:
duplicateSlice := make([]*Outer, 0, len(originalSlice))
to create a slice of length 0 but capacity of len(originalSlice). This works fine, as you can see here.
Alternatively, you could keep make([]*Outer, len(originalSlice)) and use indexing instead of append in your loop:
for i, originalItem := range originalSlice {
duplicateSlice[i] =&Outer{
InnerStruct: &Inner{
InnerVal: originalItem.InnerStruct.InnerVal + 1,
},
OuterVal: originalItem.OuterVal + 1,
}
}
Which works just as well, as you can see here.

Aerospike golang ListInsertOp multiple values

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

range over addressess of struct array

I have a struct array of type []Struct. When I range over it in the form:
for i, val := range mystructarray
I understand that val is a local variable which contains a copy of mystructarray[i]. Is there a better way of iterating through the addressess of mystructarray than this:
for i := range mystructarray{
valptr = &mystructarray[i]
}
?
There is no way to iterate while receiving a pointer to the contents of the slice (unless of course, it is a slice of pointers).
Your example is the best way:
for i := range mySlice {
x = &mySlice[i]
// do something with x
}
Remember however, if your structs aren't very large, and you don't need to operate on them via a pointer, it may be faster to copy the struct, and provide you with clearer code.

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