Golang interface benefits - go

I read about the interfaces a lot and I think I understand how it works. I read about the interface{} type and use it to take an argument of function. It is clear. My question (and what I don't understand) is what is my benefit if I am using it. It is possible I didn't get it entirely but for example I have this:
package main
import (
"fmt"
)
func PrintAll(vals []interface{}) {
for _, val := range vals {
fmt.Println(val)
}
}
func main() {
names := []string{"stanley", "david", "oscar"}
vals := make([]interface{}, len(names))
for i, v := range names {
vals[i] = v
}
PrintAll(vals)
}
Why is it better than this:
package main
import (
"fmt"
)
func PrintAll(vals []string) {
for _, val := range vals {
fmt.Println(val)
}
}
func main() {
names := []string{"stanley", "david", "oscar"}
PrintAll(names)
}

If you're always want to print string values, then the first using []interface{} is not better at all, it's worse as you lose some compile-time checking: it won't warn you if you pass a slice which contains values other than strings.
If you want to print values other than strings, then the second with []string wouldn't even compile.
For example the first also handles this:
PrintAll([]interface{}{"one", 2, 3.3})
While the 2nd would give you a compile-time error:
cannot use []interface {} literal (type []interface {}) as type []string in argument to PrintAll
The 2nd gives you compile-time guarantee that only a slice of type []string is passed; should you attempt to pass anything other will result in compile-time error.
Also see related question: Why are interfaces needed in Golang?

Related

Can 'map' and 'reduce' be implemented in Go with generics

I decided that now that generics have been introduced into Go that something like map/reduce should be possible. So, I took a naive stab at it and I get the error:
./prog.go:18:36: cannot use thing (variable of type int) as type I in argument to mapper
Which doesn't explain if the problem is fundamental or I am simply doing something wrong syntactically. Can generic map/reduce be implemented in Go?
package main
import "fmt"
func main() {
things := []int{1, 2, 3, 4}
results := Map(things, func(t int) int {
return t + 1
})
fmt.Printf("%v", results)
}
func Map[I interface{}, O interface{}](things []I, mapper func(thing I) O) []O {
results := make([]O, 0, len(things))
for thing := range things {
results = append(results, mapper(thing))
}
return results
}
You have incorrect use of range. A single variable extracted from range will be the index (type int), not the value (type I, which is only coincidentally int in this case).
Try
for _, thing := range things{...}
This can be done quite easily. You have an error in your code, though right here:
for thing := range things {
You are iterating over the index values (int), not the values of type I. You're also specifying 2 constraints (types I and O) both set to be interface{}. You can just use any instead (it's shorthand for interface{})
So simply write:
func Map[T any, O any](things []T, mapper func(thing T) O) []O {
result := make([]O, 0, len(things))
for _, thing := range things {
result = append(result, mapper(thing))
}
return result
}
Demo
This is quite closely related to some code I reviewed on codereview exchange here. After going through the code, and writing snippets with a ton of suggestions, I decided to just create a package and throw it up on github instead. You can find the repo here.
In it, there's some examples that may come in handy, or help you work through some other quirks WRT generics in golang. I wsa specifically thinking about this bit, where you can filter a generic map type using callbacks like so:
// given the sMap type
type sMap[K comparable, V any] struct {
mu *sync.RWMutex
m map[K]V
}
// Filter returns a map containing the elements that matched the filter callback argument
func (s *sMap[K, V]) Filter(cb func(K, V) bool) map[K]V {
s.mu.RLock()
defer s.mu.RUnlock()
ret := make(map[K]V, len(s.m))
for k, v := range s.m {
if cb(k, v) {
ret[k] = v
}
}
return ret
}

Function that takes map and only cares about key type

I have two maps, both of them are keyed by strings, but the values are of two different custom types.
map[string]type1
map[string]type2
Now I want to write a function which can take an argument of either of these two types, because that function only looks at the keys and doesn't care about the values at all. So I think it should look like this:
func takeTheMap(argument map[string]interface{}) {
...
But that doesn't work due to:
cannot use myVariable (type map[string]customType) as type map[string]interface {} in argument to takeTheMap
https://play.golang.org/p/4Xkhi4HekO5
Can I make that work somehow?
The only polymorphism in Go is interfaces. The only alternatives to that are reflection, duplication, or rethinking the broader design so that you don't need to do what you're trying to do here.
If the last option isn't a possibility, personally I would recommend duplication, since it's a whole four lines of code.
keys := make([]string, 0, len(myMap))
for key,_ := range myMap {
keys = append(keys,key)
}
A big complicated generic helper seems kind of unnecessary.
A solution using an interface. This example may seem a bit overkill and it may be better to in your case (I'm not sure, not enough details in your example) to just use a couple of for loops.
package main
import (
"fmt"
)
type foo bool
type bar string
type mapOne map[string]foo
type mapTwo map[string]bar
func (m mapOne) Keys() []string {
s := []string{}
for k := range m {
s = append(s, k)
}
return s
}
func (m mapTwo) Keys() []string {
s := []string{}
for k := range m {
s = append(s, k)
}
return s
}
type ToKeys interface {
Keys() []string
}
func main() {
m1 := mapOne{"one": true, "two": false}
m2 := mapTwo{"three": "foo", "four": "bar"}
doSomething(m1)
doSomething(m2)
}
func doSomething(m ToKeys) {
fmt.Println(m.Keys())
}
Playground example

Interface conversion in slice of slice

I wrote this example code (https://play.golang.org/p/u_oz5X4aU07):
func main() {
var obj interface{}
json.Unmarshal([]byte("[[1,2],[3,4]]"), &obj)
val := obj.([][]int)
fmt.Println(val)
}
Why I get the error:
interface conversion: interface {} is []interface {}, not [][]int
Is there a simple way to transform obj in a slice of slice?
This code works, but I'd like something more compact and efficient.
var val [][]float64
for r, v := range obj.([]interface{}) {
val = append(val,nil)
for _, w := range v.([]interface{}) {
val[r] = append(val[r], w.(float64))
}
}
No, ultimately you'll have to loop over the two slices!
You can read here why you can't just use one as the other:
https://research.swtch.com/interfaces
This answer might also be useful:
Why golang struct array cannot be assigned to an interface array
Essentially it's because the interface is stored as a 2 word pair, one defining the type and one the values.
You have to manually convert to the required type by visiting all the values in for-range loops.

Get rid of empty JSON values from map of interface{}

I have a struct in which I put all excess data into a map[string]interface{}.
If I unmarshal into the Data property with an empty variable, I don't want to keep it when marshalling. I basically need interface{} to have json:",omitempty", How do I get that?
type Event struct {
From string `json:"from"`
Data map[string]interface{} `json:"data,omitempty"`
}
The omitempty is for encoding values, but not for decoding.
You cannot generate a complete empty map in Go. (Empty as in, it does not exists.) If your create a variable / value of a struct it always has its default value.
package main
import "fmt"
func main() {
var m map[string]interface{}
fmt.Printf("%v %d\n", m, len(m))
// prints: map[] 0
m = nil
fmt.Printf("%v %d\n", m, len(m))
// prints: map[] 0
}
Example: Go Playground.
I'd like to know if there's anything native that supports it. However until then, you can do it via reflection:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func main() {
m := map[string]interface{}{
"should_exist": "foo",
"should_omit": "",
}
for k, v := range m {
if reflect.ValueOf(v).IsZero() {
delete(m, k)
}
}
data, _ := json.Marshal(m)
fmt.Println(string(data)) // {"should_exist":"foo"}
}
Please note the performance hit this might cause in some use cases.

interface{} variable to []interface{}

I have an interface{} variable and I know it's a pointer to slice:
func isPointerToSlice(val interface{}) bool {
value := reflect.ValueOf(val)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}
But I'm finding difficult to type cast it into an []interface{} variable:
if isPointerToSlice(val) {
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
// 'worked' is false :(
}
This doesn't work. Any idea how can I solve this?
If you just want to convert a slice to []interface{} you can use something like this:
func sliceToIfaceSlice(val interface{}) []interface{} {
rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
// panic("expected a slice or array")
return nil
}
out := make([]interface{}, rf.Len())
for i := range out {
out[i] = rf.Index(i).Interface()
}
return out
}
playground
You can simply use type assertion to obtain the value stored in an interface, e.g.
if isPointerToSlice(val) {
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
} else {
fmt.Println("Not *[]interface{}")
}
The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.
Using short variable declaration:
result := *val.(*[]interface{}) // type of result is []interface{}
Try it on the Go Playground.
Also your attempt also works:
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)
Here's the edited the Playground example which proves your solution works.
But using reflection is unnecessary (as it can be done with type assertion).
Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.
Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.
Using this method, you can shorten your code to just:
package main
import (
"fmt"
)
func main() {
s := []interface{}{"one", 2}
p := &s
do(p)
}
func do(val interface{}) {
switch val.(type){
case *[]interface{}:
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
}
}
Playground: http://play.golang.org/p/DT_hb8JcVt
The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

Resources