"Cannot use variable of type []struct as []interface" while spreading [duplicate] - go

This question already has answers here:
slice of struct != slice of interface it implements?
(6 answers)
Closed 10 months ago.
Prototype function
func test(i ...interface{}) {
// Code here
}
Intended use
type foo struct {
// Fields
}
foos := []foo{
// foo1, foo2 ...
}
test(foos...) // ERROR
test(foos[1], foos[2], ...) // OK
Error
cannot use foos (variable of type []foos) as []interface{} value in argument to test
Description
The intended use is to be used like the built-in function append().
https://golang.google.cn/pkg/builtin/#append
func append(slice []Type, elems ...Type) []Type
Although, as I've seen append() doesn't use interface{}, which is strange, since anywhere that I searched all people say to use interface{} when you don't know the type. But they don't.
Nope, append() uses a "build-in" type called Type, which apparently the docs say that it's a int. Although, I cannot use it. There isn't such type. And neither I would know how to use it if there was.
https://golang.google.cn/pkg/builtin/#Type
type Type int
So, I'm very confused here.
Questions
Why does the spread operator not work as intended? For example, in Javascript the spread operator just spreads the array into items. But in Golang it seems like it keeps the same array parameter type as it is but gives the compiler later an instruction to spread it. Which is odd.
Are we even able to make similar custom mechanisms like append() at all? Or am I a dummy and I'm using something wrong anyway?

I think that this is the issue that you are running into here.
https://github.com/golang/go/wiki/InterfaceSlice
I am not an expert in this but have hit this before, the "slice of empty interface" is not an interface and therefore cannot be replaced by any type which is the issue that you are having, it has to do with the memory structure being different. The above has a far better explanation than one that I can give.

You can typecast your typed slice to get what you need:
generic := make([]interface{}, 0)
for _, f := range foos {
generic = append(generic, f)
}
test(generic...) // works

Combining the two non-negative answers into what I feel is the best solution:
interfaceSlice := make([]interface{}, len(foos))
for i, v := range foos {
interfaceSlice[i] = v
}
test(interfaceSlice...)
Partially inspired by:
https://github.com/golang/go/wiki/InterfaceSlice#what-can-i-do-instead

Related

Assign a string to a struct via reflect [duplicate]

This question already has an answer here:
Update an attribute in a struct with reflection
(1 answer)
Closed 1 year ago.
I have a struct, where I wish to dynamically change a string to another string using reflect. My issue is that the new string is created on the stack, and therefore the Set() method panics.
This makes sense to me, but I don't know how to fix it. I'm not sure the easy way to declare a string as addressable or if there's a different reflection technique to use.
type MyStruct struct {
SomeField string
}
func main() {
myStruct := MyStruct{"initial"}
hello := "hello world"
field := reflect.ValueOf(myStruct).FieldByName("SomeField")
helloValue := reflect.ValueOf(hello)
fmt.Printf("hello is on the stack, canAddr is %v\n", helloValue.CanAddr())
// This will panic because canAddr is false
field.Set(helloValue)
}
https://play.golang.org/p/ghUgiQfKXhk
The go error is a bit of a misnomer. The problem is with the struct, not the string.
The problem is in this line:
field := reflect.ValueOf(myStruct).FieldByName("SomeField")
Calling ValueOf passes in a copy (of myStruct in this case). Since changing a copy won't change myStruct, then go panics (helpfully, if cryptically). See [the third law of reflection] (https://blog.golang.org/laws-of-reflection#TOC_8)
Changing this line to field := reflect.ValueOf(&myStruct).Elem().FieldByName("SomeField") fixes the error (note the & to take the address, and then Elem() to dereference)
Of course I only figure this out after posting the question but hopefully it will help someone else

Function that returns Slice of Custom Interface

At first, I want to introduce you because I feel like I am missing some core Golang concept.
In my application, many models will have a method called GetByUserId. I created interface(UserCreatedEntity) that requires this method so then I will be able to create Controller's GetUserRecords method factory for each type of records with just:
router.Handle("/ideas/mine",
middlewares.AuthUser(controllers.GetMineFactory(&models.Idea{}))).Methods("POST")
router.Handle("/votes/mine",
middlewares.AuthUser(controllers.GetMineFactory(&models.Vote{}))).Methods("POST")
router.Handle("/someNewType/mine",
middlewares.AuthUser(controllers.GetMineFactory(&models.SomeNewType{}))).Methods("POST")
This is how my interface looks like:
type UserCreatedEntity interface {
GetByUserId(userId uint) []UserCreatedEntity
}
And implementation:
func (idea *Idea) GetByUserId(userId uint) []UserCreatedEntity {
ideas := []Idea{}
GetDB().
Table("ideas").
/** Query removed to make code less confusing **/
Scan(ideas)
return ideas
}
Obviously, it does not work (version with slice of pointers neither do). The thing is - This code would work if I return only one record - like that (obviously with changing signature in interface also):
func (idea *Idea) GetByUserId(userId uint) UserCreatedEntity {
idea := &Idea{}
GetDB().
Table("ideas").
/** Query removed to make code less confusing **/
First(idea)
return idea
}
How to make it work as slice? As I said I suspect that I am missing some important knowledge. So deep explaination would be awesome.
Solution:
func (idea *Idea) GetByUserId(userId uint) []UserCreatedEntity {
ideas := []*Idea{}
GetDB().
Table("ideas").
Select("problems.name AS problem_name, ideas.id, ideas.problem_id, ideas.action_description, ideas.results_description, ideas.money_price, ideas.time_price, ideas.is_published").
Joins("INNER JOIN problems ON ideas.problem_id = problems.id").
Where("ideas.user_id = ?", userId).
Scan(&ideas)
uces := make([]UserCreatedEntity, len(ideas))
for i, idea := range ideas {
uces[i] = idea
}
return uces
}
In programming language theory this is called variance, and it is not supported in Go. For much more details see this proposal.
Specifically, return types are not covariant. A slice of T does not implement a slice of I even if T implements I.
The FAQ entry linked above proposes this workaround:
It is necessary to copy the elements individually to the destination
slice. This example converts a slice of int to a slice of interface{}:
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
Though in your case the right solution may be different.
Interfaces are dynamic. Composite types that involve interfaces are not.
UserCreatedEntity is an interface, and Idea satisfies the interface, so you can return an Idea from a function whose signature has a return type of UserCreatedEntity.
[]UserCreatedEntity is a slice of UserCreatedEntity, not an interface. The only type that can be returned is []UserCreatedEntity. []Idea is a different type (slice of Idea). You can fill a []UserCreatedEntity with Idea elements, because each element is of type UserCreatedEntity, which again is an interface and Idea is allowed there.
Similarly, func() UserCreatedEntity is a type "function which returns UserCreatedEntity". You cannot subsitute a func() Idea because that is a different type. But you can return an Idea from a func() UserCreatedEntity because an Idea is a UserCreatedEntity.
If you weren't using Scan here, which presumably uses reflection, the fix would be to declare your local slice as []UserCreatedEntity instead of []Idea. Since you are using Scan, you instead must scan into a []Idea, then iterate over it to copy all the elements to a []UserCreatedEntity and return that.

How to list pointers to all fields of golang struct?

Is there a good way in golang to pass all fields of some struct instance c?
I'm looking for some syntactic sugar functionality, so that instead of doing this:
method(&c.field1, &c.field2, &c.field3, &c.field4, &c.field5, ...)
I could do this:
method(FieldsPointers(c)...)
I'm rather new to golang and still learning the basics, if there is no good way to do what I want for a good reason, I'd appreciate an explanation as to why.
Besides all sql specified tools, if you want to access to pointers of a struct, you can use reflect. Be warned that the package is tricky and rob pike said it is not for everyone.
reflect.Value has methods NumField which returns the numbber of fields in the struct and Field(int) which accepts the index of a field and return the field itself.
But as you want to set a value to it, it is more complicated than just calling the two methods. Let me show you in code:
func Scan(x interface{}) {
v := reflect.ValueOf(x).Elem()
for i := 0; i < v.NumField(); i++ {
switch f := v.Field(i); f.Kind() {
case reflect.Int:
nv := 37
f.Set(reflect.ValueOf(nv))
case reflect.Bool:
nv := true
f.Set(reflect.ValueOf(nv))
}
}
}
First, you need to pass a pointer of the struct into Scan, since you are modifying data and the value must be settable. That is why we are calling .Elem(), to dereference the pointer.
Second, reflect.Value.Set must use a same type to set. You cannot set uint32 to a int64 like normal assignment.
Playground: https://play.golang.org/p/grvXAc1Px8g

Express function that takes any slice

I want to express a function that can take any slice. I thought that I could do this:
func myFunc(list []interface{}) {
for _, i := range list {
...
some_other_fun(i)
...
}
}
where some_other_fun(..) itself takes an interface{} type. However, this doesn't work because you can't pass []DEFINITE_TYPE as []interface{}. See: https://golang.org/doc/faq#convert_slice_of_interface which notes that the representation of an []interface{} is different. This answer sums up why but with respect to pointers to interfaces instead of slices of interfaces, but the reason is the same: Why can't I assign a *Struct to an *Interface?.
The suggestion provided at the golang.org link above suggests rebuilding a new interface slice from the DEFINITE_TYPE slice. However, this is not practical to do everywhere in the code that I want to call this function (This function is itself meant to abbreviate only 9 lines of code, but those 9 lines appear quite frequently in our code).
In every case that I want to invoke the function I would be passing a []*DEFINITE_TYPE which I at first thought would be easier to abstract until, again, I discovered Why can't I assign a *Struct to an *Interface? (also linked above).
Further, everytime I want to invoke the function it is with a different DEFINITE_TYPE so implementing n examples for the n types would not save me any lines of code or make my code any clearer (quite the contrary!).
It is frustrating that I can't do this since the 9 lines are idiomatic in our code and a mistype could easily introduce a bug. I'm really missing generics. Is there really no way to do this?!!
In the case you provided, you would have to create your slice as a slice of interface e.g. s := []interface{}{}. At which point you could literally put any type you wanted into the slice (even mixing types). But then you would have to do all sorts of type assertions and everything gets really nasty.
Another technique that is commonly used by unmarshalers is a definition like this:
func myFunc(list interface{})
Because a slice fits an interface, you can indeed pass a regular slice into this. You would still need to do some validation and type assertions in myFunc, but you would be doing single assertions on the entire list type, instead of having to worry about a list that could possibly contain mixed types.
Either way, due to being a statically typed language, you eventually have to know the type that is passed in via assertions. It's just the way things are. In your case, I would probably use the func signature as above, then use a type switch to handle the different cases. See this document https://newfivefour.com/golang-interface-type-assertions-switch.html
So, something like this:
func myFunc(list interface{}) {
switch v := list.(type) {
case []string:
// do string thing
case []int32, []int64:
// do int thing
case []SomeCustomType:
// do SomeCustomType thing
default:
fmt.Println("unknown")
}
}
No there is no easy way to deal with it. Many people miss generics in Go.
Maybe you can get inspired by sort.Sort function and sort.Interface to find a reasonable solution that would not require copying slices.
Probably the best thing to do is to define an interface that encapsulates what myFunc needs to do with the slice (i.e., in your example, get the nth element). Then the argument to the function is that interface type and you define the interface method(s) for each type you want to pass to the function.
You can also do it with the reflect package, but that's probably not a great idea since it will panic if you pass something other than a slice (or array or string).
func myFunc(list interface{}) {
listVal := reflect.ValueOf(list)
for i := 0; i < listVal.Len(); i++ {
//...
some_other_fun(listVal.Index(i).Interface())
//...
}
}
See https://play.golang.org/p/TyzT3lBEjB.
Now with Go 1.18+, you can use the generics feature to do that:
func myFunc[T any](list []T) {
for _, item := range list {
doSomething(item)
}
}

Variadic generic arguments in Go [duplicate]

This question already has answers here:
Generic variadic argument in Go?
(3 answers)
Closed 8 months ago.
Let's say I want to make the equivalent of the JavaScript Array.splice function in Go, for Slices. I have the following code:
func splice(slice []int, index, amount int, elements ...int) []int {
newslice := make([]int, 0)
for i := 0; i < index; i++ {
newslice = append(newslice, slice[i])
}
for i := index + amount; i < len(slice); i++ {
newslice = append(newslice, slice[i])
}
for _, el := range elements {
newslice = append(newslice, el)
}
return newslice
}
This example will work, but only for arguments of type int. I want to make it generic, and I know that I should give the variadic argument elements the type interface{}, but how do I create a new slice with the type of that interface from inside the function?
In other words, how can I specify the type of the slice dynamically depending on the type of the arguments in the first line of the function, where newslice is created?
Using reflection
If you really want to do generic stuff, reflection is the ultimate answer.
See the MakeSlice documentation
in the reflection package for details on your problem.
You just need to retrieve the type of the incoming slice (using TypeOf(...))
and applying MakeSlice correctly.
Example of using reflection to create a slice:
y := []int{1,2,3}
t := reflect.TypeOf(y)
slice := reflect.MakeSlice(t, 0, 10)
slice = reflect.Append(slice, reflect.ValueOf(2))
fmt.Println(slice.Interface())
Run it here.
Using []interface{}
Another way to work with, is []interface{}, which can store any value
but may lead to runtime panics as you omit compiler type checking completely
(this is a bad thing).
Here is an example for using []interface{}
as storage for arbitrary values. With this you don't need to know the type in
your splice implementation, you just splice and use []interface{} for new slices.
This method has the drawback, that you can't convert some slice to []interface{} easily. You have to copy it manually, as described in posts before.
Conclusion
Regardless of which version you use, you will never get back type safety without
knowing the type and converting it back manually. There's no such thing in Go
which will do that for you. That means, that you'll have something like this
in your code to regain type safety:
x := []int{1,2,3,4}
y := splice(x, ...)
yn := []int(y)
Instead of emulating JavaScript in Go (why ???) I would like to suggest to compose simmilar required operations from the building blocks of SliceTricks.
They are:
Completely type agnostic (think "generics" for free).
Quite probably pretty faster compared to packing/unpacking whatsoever in/from a []interface{}.

Resources