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
Related
I'm a beginner in using golang, I'm still confused about creating a slice for the child model, after that I want to take index "0" and convert it from *uint64 to *int64. Maybe i'm wrong way to convert the field, but i think i need to make the child model into a slice first before converting it. Here is the code :
params := category.PostAPICategoryParams{
Data: category.PostAPICategoryBody{
CategoryData: categoryTestData.CategoryData,
Childs: categoryTestData.Childs,
},
}
result, _ := mainSuite.h.CreateCategory(mainSuite.rt, ¶ms.Data.CategoryData, params.Data.Childs)
categoriesParamsTest := &category.GetAPICategoryParams{
ParentID: // here is the code I need to write,
}
Here is the error when I try to write the code before creating the slice :
You have a pointer to a uint64, and want a pointer to a int64. There's no direct (safe) way to do this -- pointers to unsigned ints aren't compatible with pointers to signed ints -- but you can convert the pointed-at value to the right type (assuming the pointer isn't nil).
For example:
func convertUnsignedToSignedPointer64(p *uint64) *int64 {
if p == nil { return nil }
x := int64(*p)
return &x
}
You can also do it via the unsafe package, although I prefer avoiding the unsafe package in code I write when possible:
func convertUnsignedToSignedPointer64(p *uint64) *int64 {
return (*int64)(unsafe.Pointer(p))
}
This is ok via the rules given in unsafe.Pointer:
(1) Conversion of a *T1 to Pointer to *T2.
Provided that T2 is no larger than T1 and that the two share an
equivalent memory layout, this conversion allows reinterpreting data
of one type as data of another type.
I have a variable that needs to be either a string or map[string]string (will be deserializing from JSON). So I declare it as interface{}. How can I check that the value is map[string]string?
This question How to check interface is a map[string]string in golang almost answers my question. But the accepted answer only works if the variable is declared as a map[string]string not if the variable is interface{}.
package main
import (
"fmt"
)
func main() {
var myMap interface{}
myMap = map[string]interface{}{
"foo": "bar",
}
_, ok := myMap.(map[string]string)
if !ok {
fmt.Println("This will be printed")
}
}
See https://play.golang.org/p/mA-CVk7bdb9
I can use two type assertions though. One on the map and one on the map value.
package main
import (
"fmt"
)
func main() {
var myMap interface{}
myMap = map[string]interface{}{
"foo": "bar",
}
valueMap, ok := myMap.(map[string]interface{})
if !ok {
fmt.Println("will not be printed")
}
for _, v := range valueMap {
if _, ok := v.(string); !ok {
fmt.Println("will not be printed")
}
}
}
See https://play.golang.org/p/hCl8eBcKSqE
Question: is there a better way?
If you declare a variable as type interface{}, it is type interface{}. It is not, ever, some map[keytype]valuetype value. But a variable of type interface{} can hold a value that has some other concrete type. When it does so, it does so—that's all there is to it. It still is type interface{}, but it holds a value of some other type.
An interface value has two parts
The key distinction here is between what an interface{} variable is, and what it holds. Any interface variable actually has two slots inside it: one to hold what type is stored in it, and one to hold what value is stored in it. Any time you—or anyone—assign a value to the variable, the compiler fills in both slots: the type, from the type of the value you used, and the value, from the value you used.1 The interface variable compares equal to nil if it has nil in both slots; and that's also the default zero value.
Hence, your runtime test:
valueMap, ok := myMap.(map[string]interface{})
is a sensible thing to do: if myMap holds a value that has type map[string]interface, ok gets set to true and valueMap contains the value (which has that type). If myMap holds a value with some other type, ok gets set to false and valueMap gets set to the zero-value of type map[string]interface{}. In other words, at runtime, the code checks the type-slot first, then either copies the value-slot across to valueMap and sets ok to true, or sets valueMap to nil and sets ok to false.
If and when ok has been set to true, each valueMap[k] value is type interface{}. As before, for myMap itself, each of these interface{} variables can—but do not have to—hold a value of type string, and you must use some sort of "what is the actual type-and-value" run-time test to tease them apart.
When you use json.Unmarshal to stuff decoded JSON into a variable of type interface{}, it is capable of deserializing any of these documented JSON types. The list then tells you what type gets stuffed into the interface variable:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
So after doing json.Unmarshal into a variable of type interface{}, you should check what type got put into the type-slot of the variable. You can do this with an assertion and an ok boolean, or you can, if you prefer, use a type switch to decode it:
var i interface
if err := json.Unmarshal(data, &i); err != nil {
panic(err)
}
switch v := i.(type) {
case string:
... code ...
case map[string]interface{}:
... code ...
... add some or all of the types listed ...
}
The thing is, no matter what you do in code here, you did have json.Unmarshal put something into an interface{}, and interface{} is the type of i. You must test at runtime what type and value pair the interface holds.
Your other option is to inspect your JSON strings manually and decide what type of variable to provide to json.Unmarshal. That gives you less code to write after the Unmarshal, but more code to write before it.
There's a more complete example here, on the Go playground, of using type switches to inspect the result from a json.Unmarshal. It's deliberately incomplete but, I think, has enough input and output cases to let you work out how to handle everything, given the quote above about what json.Unmarshal writes into a variable of type interface{}.
1Of course, if you assign one interface{} from some other interface{}:
var i1, i2 interface{}
... set i1 from some actual value ...
// more code, then:
i2 = i1
the compiler just copies both slots from i1 into i2. The two-separate-slots thing becomes clearer when you do:
var f float64
... code that sets f to, say, 1.5 ...
i2 = f
for instance, as that writes float64 into the type-slot, and the value 1.5 into the value-slot. The compiler knows that f is float64 so the type-setting just means "stick a constant in it". The compiler doesn't necessarily know the value of f so the value-setting is a copy of whatever the actual value is.
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.
The slices are references to the underlying array. This makes sense and seems to work on builtin/primitive types but why is not working on structs? I assume that even if I update a struct field the reference/address is still the same.
package main
import "fmt"
type My struct {
Name string
}
func main() {
x := []int{1}
update2(x)
fmt.Println(x[0])
update(x)
fmt.Println(x[0])
my := My{Name: ""}
update3([]My{my})
// Why my[0].Name is not "many" ?
fmt.Println(my)
}
func update(x []int) {
x[0] = 999
return
}
func update2(x []int) {
x[0] = 1000
return
}
func update3(x []My) {
x[0].Name = "many"
return
}
To clarify: I'm aware that I could use pointers for both cases. I'm only intrigued why the struct is not updated (unlike the int).
What you do when calling update3 is you pass a new array, containing copies of the value, and you immediately discard the array. This is different from what you do with the primitive, as you keep the array.
There are two approaches here.
1) use an array of pointers instead of an array of values:
You could define update3 like this:
func update3(x []*My) {
x[0].Name = "many"
return
}
and call it using
update3([]*My{&my})
2) write in the array (in the same way you deal with the primitive)
arr := make([]My,1)
arr[0] = My{Name: ""}
update3(arr)
From the GO FAQ:
As in all languages in the C family, everything in Go is passed by
value. That is, a function always gets a copy of the thing being
passed, as if there were an assignment statement assigning the value
to the parameter. For instance, passing an int value to a function
makes a copy of the int, and passing a pointer value makes a copy of
the pointer, but not the data it points to. (See the next section for
a discussion of how this affects method receivers.)
Map and slice values behave like pointers: they are descriptors that
contain pointers to the underlying map or slice data. Copying a map or
slice value doesn't copy the data it points to.
Thus when you pass my you are passing a copy of your struct and the calling code won't see any changes made to that copy.
To have the function change the data in teh struct you have to pass a pointer to the struct.
Your third test is not the same as the first two. Look at this (Playground). In this case, you do not need to use pointers as you are not modifying the slice itself. You are modifying an element of the underlying array. If you wanted to modify the slice, by for instance, appending a new element, you would need to use a pointer to pass the slice by reference. Notice that I changed the prints to display the type as well as the value.
In Go, in order to iterate over an array/slice, you would write something like this:
for _, v := range arr {
fmt.Println(v)
}
However, I want to iterate over array/slice which includes different types (int, float64, string, etc...). In Python, I can write it out as follows:
a, b, c = 1, "str", 3.14
for i in [a, b, c]:
print(i)
How can I do such a work in Go? As far as I know, both array and slice are supposed to allow only same-type object, right? (say, []int allows only int type object.)
Thanks.
As Go is a statically typed language, that won't be as easy as in Python. You will have to resort to type assertions, reflection or similar means.
Take a look at this example:
package main
import (
"fmt"
)
func main() {
slice := make([]interface{}, 3)
slice[0] = 1
slice[1] = "hello"
slice[2] = true
for _, v := range slice {
switch v.(type) {
case string:
fmt.Println("We have a string")
case int:
fmt.Println("That's an integer!")
// You still need a type assertion, as v is of type interface{}
fmt.Printf("Its value is actually %d\n", v.(int))
default:
fmt.Println("It's some other type")
}
}
}
Here we construct a slice with the type of an empty interface (any type implements it), do a type switch and handle the value based on the result of that.
Unfortunately, you'll need this (or a similar method) anywhere where you'll be dealing with arrays of unspecified type (empty interface). Moreover, you'll probably need a case for every possible type, unless you have a way to deal with any object you could get.
One way would be to make all of the types you want to store implement some interface of yours and then only use those objects through that interface. That's kind of how fmt handles generic arguments – it simply calls String() on any object to get its string representation.