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

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.

Related

Go using generic slice field in struct

We want to have
type ResponseListDataPayload struct {
List []*interface{} `json:"list"` //generic
TotalCnt int64 `json:"totalCnt"`
Page int64 `json:"page"`
Step int64 `json:"step"`
}
and List could would accept []*model.SomeModel{}
queryResults := []*model.SomeModel{}
resposeResult := &ResponseListDataPayload{
List: queryResults,
TotalCnt: cnt,
Page: pageInt,
Step: stepInt,
}
or []*model.AnotherModel{}
queryResults := []*model.AnotherModel{}
resposeResult := &ResponseListDataPayload{
List: queryResults,
TotalCnt: cnt,
Page: pageInt,
Step: stepInt,
}
That's pretty straightforward in Java, could that be possible in go?
Go 1.18
You can now have parametrized structs:
type ResponseListDataPayload[T any] struct {
List []T `json:"list"` //generic
TotalCnt int64 `json:"totalCnt"`
Page int64 `json:"page"`
Step int64 `json:"step"`
}
Remember that generic structs must be instantiated with an explicit type parameter:
queryResults := []*model.SomeModel{}
responseResult := &ResponseListDataPayload[*model.SomeModel]{
List: queryResults,
// other fields
}
If you want to improve code reuse even more and "genericize" also the struct initialization, you can use a constructor function. Functions can take advantage of type inference to omit writing out the type arguments:
// add to func signature other arguments as needed
func NewResponseFor[T any](list []T) *ResponseListDataPayload[T] {
return &ResponseListDataPayload[T]{ List: list }
}
and use it as:
queryResults := // some query results
responseResult := NewResponseFor(queryResults)
Example: https://gotipplay.golang.org/p/jYTHegaeubR
Go 1.17 and below
could that be possible in go?
No, interface{} is not actually a generic type, it's just an interface with an empty method set.
Formally, you can assign any concrete value to it because assignability requires the value's method set to be a superset of the interface method set, and any set is a superset of the empty set (∅).
It's not the same thing as a parametrized type like Java's List<T> hence in Go []Foo is not assignable to []interface{}.
You must process the single elements in a loop:
var m []*model.anotherModel
// populate m
for _, v := range m {
resp.List = append(resp.List, v)
}
Similarly, don't use pointers to the empty interface *interface{}. Use interface{} instead.
If your goal is to just serialize JSON (based on the presence of the tags on your struct), you can declare the List field as interface{} and you’ll be able to assign either of your slice values to it, for the reason stated above. Thus avoiding an extra slice manipulation. The json package will then serialize based on the concrete values boxed in the interface{}.
In Go 1.18 you will be able to do something like, with real go generics:
func convert[S any](src []S) []interface{} {
dst := make([]interface{}, 0, len(src))
for _, v := range src {
dst = append(dst, v)
}
return dst
}
//...
resp.List = convert(m)
But until 1.18 is out and more codebases embrace generics, you will still need to do the conversion by hand.
And like everyone said, don't use *interface{}.

Golang Reflection: Inspect a struct type definition to extract its properties without initialization

If I have the following declaration
type Foo struct {
bar string
}
Can I use reflection to inspect the properties on the declaration without initialising it?
keys := reflect.something(Foo)
for _, key := range keys {
fmt.Println(key) // "bar"
}
Use reflect.TypeOf to get the reflect.Type for Foo.
t := reflect.TypeOf(Foo{})
If you don't want to create a value of the type, then get the pointer type and "dereference" that type.
t := reflect.TypeOf((*Foo)(nil)).Elem()
The expression (*Foo)(nil) returns a nil pointer to the type. The Type.Elem method returns the pointed to type.
Iterate through the fields on the type. Type.NumField returns the number of fields on the type. Type.Field returns a StructField by field index.
for i := 0; i < t.NumField; i++ {
fmt.Println(t.Field(i).Name)
}
Run it on the playground.

How to check variable declared as map[string]interface{} is actually map[string]string?

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.

Convert array to interface{} to slice, but the result can not use len() and other method

I tried :
var a [100]int
func fun1(src interface{}) interface{} {
src, _ = src.([100]int) // changed []int to [100]int
fmt.Println(reflect.TypeOf(src)) // result: []int
dest := make([]int, len(src))
return dest
}
there is an error:
message: 'invalid argument src (type interface {}) for len'
But if I redefine a variable:
var a [100]int
func fun1(src interface{}) interface{} {
slice_src, _ := src.([100]int) //changed []int to [100]int
fmt.Println(reflect.TypeOf(slice_src)) // result: []int
dest := make([]int, len(slice_src))
return dest
}
it will be ok.
why reflect.TypeOf(src) will print []int after I used src.([]int) but error shows src is still interface{} ?
I have checked this convert interface{} to int, but I still don't understand how to use correct conversion.
There is another question:
I changed the []int to [100]int since the type assertion before will return [] and false.
But if I don't know the type of a, how can I use type assertion to transfer an array (like[99]int) as a interface{} to function and return slice ([]int)?
when you first declare src, in fun1(src interface{}) you are making a variable of type interface. Which, of course cannot have len called on it.
The reason reflect.TypeOf says []int is due to how TypeOf works.
It takes an interface{} and tells you the type of the thing in the interface{}
so, in the first example, you already had an interface
and in the second example, go automatically created an interface{} instance to hold your []int slice.
Quoting dynamic type from Variables :
The static type (or just type) of a variable is the type given in its declaration, the type provided in the new call or composite literal, or the type of an element of a structured variable. Variables of interface type also have a distinct dynamic type, which is the concrete type of the value assigned to the variable at run time (unless the value is the predeclared identifier nil, which has no type). The dynamic type may vary during execution but values stored in interface variables are always assignable to the static type of the variable.
In the first example, src has a dynamic type. Value of the src will be of type []int during execution but eventually, type will be interface since it is dynamic type & it was of type interface at the time of declaration. Hence, you need to change variable src to the new variable during type assertion.
Similar to what you did in second example: slice_src, _ := src.([]int)
You can not even do src, _ := src.([]int) as you will end up with error no new variables on left side of :=
There is a type switch method using reflect.TypeOf() : golang type assertion using reflect.Typeof()
and
How to get the reflect.Type of an interface?
Quote How to get the reflect.Type of an interface? :
You can't. Type assertions allow you to take advantage of the static type checking that the language gives you even if you have an interface, whose type isn't statically checked. It basically works something like this:
You have some statically typed variable s, which has type t. The compiler enforces the guarantee that s always has type t by refusing to compile if you ever try to use s as if it were a different type, since that would break the guarantee.

golang: accessing value in slice of interfaces

I have a data structure which comes of out go-spew looking like this:
([]interface {}) (len=1 cap=1) {
(string) (len=1938) "value"
}
It is of type []interface {}
How can I print this value with fmt, or access it in some way so that I can use it.
You can use type assertions or reflection work with the generic interface{} to an underlying type. How you do this depends on your particular use case. If you can expect the interface{} to be a []interface{} as in your example, you can:
if sl, ok := thing.([]interface{}); ok {
for _, val := range sl {
fmt.Println(val)
// Or if needed, coerce val to its underlying type, e.g. strVal := val.(string)
}
}
(Playground link)
If you can't make assumptions about the underlying type, you'll need to do some black magic using reflect.

Resources