Parameter that's a list of interface{} [duplicate] - go

This question already has an answer here:
Passing interface{} or []interface{} in Golang
(1 answer)
Closed 4 years ago.
I'm trying to create a function that prints out the len of a list passed into it, regardless of the type of the list. My naive way of doing this was:
func printLength(lis []interface{}) {
fmt.Printf("Length: %d", len(lis))
}
However, when trying to use it via
func main() {
strs := []string{"Hello,", "World!"}
printLength(strs)
}
It complains saying
cannot use strs (type []string) as type []interface {} in argument to printLength
But, a string can be used as a interface{}, so why can't a []string be used as a []interface{}?

You can use reflect package - playground
import (
"fmt"
"reflect"
)
func printLength(lis interface{}) {
fmt.Printf("Length: %d", reflect.ValueOf(lis).Len())
}

Related

How to pass a slice of type A to a function that take a slice of interface that is implemented by A elegantly? [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 7 days ago.
I have two types AssetClips and Videos that implement the interface call timelineClip.
I wanted to pass a []AssetClips or a []Videos to a function that take as argument a []timelineClip but the compiler was complaining, I don't really understand why. I ended up doing a for loop to convert my []AssetClips and my []Videos to []timelineClip
Is it necessary and is there a more elegant way of doing that?
// myFunctionThatTakesASliceOfTimelineClips(assetClips) is not possible
// myFunctionThatTakesASliceOfTimelineClips(videos) is not possible
var timelineClips []timelineClip
for _, assetClip := range assetClips {
timelineClips = append(timelineClips, assetClip)
}
for _, video := range videos {
timelineClips = append(timelineClips, video)
}
myFunctionThatTakesASliceOfTimelineClips(timelineClips)
It is necessary, and this is an elegant way to do it.
This is necessary because the mechanics of passing a slice of interface is different from the mechanics of passing a slice of structs. Each element of a slice of structs is a copy of the struct itself, whereas the elements of an interface is an interface pointing to an instance of a struct, together with its type.
If you want to avoid copying, you could use a generics for this. In short, you just change signature of
func myFunctionThatTakesASliceOfTimelineClips(timelineClips []timelineClip)
to
func myFunctionThatTakesASliceOfTimelineClips[T timelineClip](timelineClips []T)
As an example:
https://go.dev/play/p/FTj8rMYq9GF
package main
import "fmt"
type Exampler interface {
Example()
}
type A struct{}
type B struct{}
func (a A) Example() {
fmt.Println("it worked")
}
func (b B) Example() {
fmt.Println("it worked")
}
func DoExample[T Exampler](tt []T) {
for _, t := range tt {
t.Example()
}
}
func main() {
aa := []A{{}}
bb := []B{{}}
DoExample(aa)
DoExample(bb)
}

Why doesn't reflect.Type{}.Implements(reflect.TypeOf(Interface(nil))) work? [duplicate]

This question already has answers here:
Golang pass nil value as an interface through reflection
(2 answers)
How to get the reflect.Type of an interface?
(3 answers)
Closed 1 year ago.
The title is a little hard to parse so here's more verbose, understandable example:
import "fmt"
import "reflect"
type Stringer interface {
String() string
}
type MyInt int
func (m MyInt) String() string {
return fmt.Sprintf("I'm number %d!", m)
}
func main() {
var m = MyInt(10)
m_type := reflect.TypeOf(m)
m_type.Implements(reflect.TypeOf(Stringer(nil))) // This does not work.
}
If you try this code, you will get a panic from within reflect.[some internal class].Implements. Why doesn't this work? Is this some weird side effect of typed nil and nil interfaces?
What's the best workaround for it? I've seen this in the wild:
m_type.Implements(reflect.TypeOf((*Stringer)(nil).Elem())) // true
It works, but it's ugly as hell. Is there a cleaner way? Why does this work when the naive approach does not?

why cannot use (type func(string)) as type func(interface{}) in assignment [duplicate]

This question already has answers here:
Type func with interface parameter incompatible error
(1 answer)
Func with interface argument not equals to func with string argument. Why?
(1 answer)
Go function types that return structs being used with interfaces
(2 answers)
Passing an arbitrary function as a parameter in Go
(4 answers)
How to convert from `func() *int` to `func() interface{}`? [duplicate]
(1 answer)
Closed 8 months ago.
Please first have a look at the code below.
package main
import "fmt"
type InterfaceFunc func(interface{})
type StringFunc func(string)
func stringFunc(s string) {
fmt.Printf("%v", s)
}
func interfaceFunc(i interface{}) {
fmt.Printf("%v", i)
}
func main() {
var i = interfaceFunc
var s = stringFunc
i = s // I would like someone to explain why this can't be done exactly.
}
Run at https://play.golang.org/p/16cE4O3eb95
Why an InterfaceFunc can't hold a StringFunc while an interface{} can hold a string.
You can not do s = i or i = s, and the reason is both functions are of different type (different signatures), you can not just assign one type with another in golang.
Also type InterfaceFunc func(interface{}) type StringFunc func(string) are sitting there doing nothing.

How to implement a generic slice appender? [duplicate]

This question already has answers here:
Appending to go lang slice using reflection
(2 answers)
Closed 8 months ago.
I'm relatively new to go. I'm trying to write a generic "appender" function. This is a simplification, but its an attempt to create a clean interface for processing some lists. Specifically, I have questions about the two errors that this generates:
package main
type GenericFunc func() *interface{}
func Append(ints interface{}, f GenericFunc) {
ints = append(ints, f())
}
func ReturnInt() *int {
i := 1
return &i
}
func main() {
var ints []*int
Append(ints, ReturnInt)
}
Playground
prog.go:5:18: first argument to append must be slice; have interface
{} prog.go:15:11: cannot use ReturnInt (type func() *int) as type
GenericFunc in argument to Append
Why can't ReturnInt be of type GenericFunc? If this doesn't work, I'm not understanding how interface{} can be used with functions at all.. can it?
How can you accept a "generic" slice and append to it using reflection? This would involve checking that GenericFunc returns the same type that the slice is, but after that appending should be possible.
The types func() *interface{} (type type of GenericFunc) and (type func() *int) (the type of ReturnInt) are different types. One returns a *interface{}. The other returns a *int. The types are not assignable to each other.
Use this function to generically append the result of a function to a slice:
func Append(sp interface{}, f interface{}) {
s := reflect.ValueOf(sp).Elem()
s.Set(reflect.Append(s, reflect.ValueOf(f).Call(nil)[0]))
}
Call it like this:
var ints []*int
Append(&ints, ReturnInt)
The function will panic if the argument is not a pointer to a slice or the function does not return a value assignable to a slice element.
playground example

Is there a way to generically represent a group of similar functions? [duplicate]

This question already has answers here:
Type func with interface parameter incompatible error
(1 answer)
Func with interface argument not equals to func with string argument. Why?
(1 answer)
Go function types that return structs being used with interfaces
(2 answers)
Passing an arbitrary function as a parameter in Go
(4 answers)
How to convert from `func() *int` to `func() interface{}`? [duplicate]
(1 answer)
Closed 8 months ago.
package main
import "fmt"
type Pet interface {
Bark()
}
type Dog int
func (d Dog) Bark() {
fmt.Println("W! W! W!")
}
type Cat int
func (c Cat) Bark() {
fmt.Println("M! M! M!")
}
type AdoptFunc func(pet Pet)
func adoptDog(dog Dog) {
fmt.Println("You live in my house from now on!")
}
func adoptCat(cat Cat) {
fmt.Println("You live in my house from now on!")
}
func main() {
var adoptFuncs map[string]AdoptFunc
adoptFuncs["dog"] = adoptDog // cannot use adoptDog (type func(Dog)) as type AdoptFunc in assignment
adoptFuncs["cat"] = adoptCat // the same as above
}
As the code above, is there a way to use a map or array to collect a bunch of similar functions adoptXxx? If not, what is right pattern to use for this situation?
To use the map as a function collection you'll have to change the signature of your functions to match. func(Pet) is not the same type as func(Dog).
You can re-write AdoptXXX functions to take in Pet and do a type select to ensure correct pet is being input:
func adoptDog(pet Pet) {
if _, ok := pet.(Dog); !ok {
// process incorrect pet type
}
fmt.Println("You live in my house from now on!")
}

Resources