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
Related
Often when using go, not sure why, I get the urge to write something like
type data []event
especially when I know I'm going to be passing the slice around without thinking too much about its contents for much of the program. Sooner or later it's going to be time to unpack some data into that slice of events and I end up writing something like:
func (d *data)Unmarshal(b []byte){
//... lots of sad code that never works
}
No matter what I do I can never quite figure out how to bless my slice type with an unmarshal method that turns some bytes into the data type in-place.
When I give up, I either write a simpler function like func UnmarshalData(b []byte) data which feels like a retreat and makes it hard to write interfaces, or change the type in the first place and make a struct like
type data struct {
actuallyTheData []event
}
which feels like boilerplate purely to compensate for my lack of understanding.
So my question is: is it possible to write a function with a pointer receiver where the receiver is a slice type and that allows me to e.g. Unmarshal in-place?
The closest I can get, though it still doesn't work (and, let's face it, is pretty ugly), is something like:
type foo []int
func (f *foo) Unmarshal(s string) {
numbers := strings.Split(s, ",")
integers := make([]int, len(numbers))
for i, n := range numbers {
integer, err := strconv.Atoi(n)
if err != nil {
log.Fatal(err)
}
integers[i] = integer
}
my_f := foo(integers)
f = &my_f
}
Here's the full example: https://go.dev/play/p/3q7qehoW9tm. Why doesn't it work? What am I misunderstanding?
The last line in your Unmarshal function is overwriting the receiver itself, i.e. its address:
f = &my_f // changing the value of the pointer
The updated value won't be propagated to callers. From Declarations and Scope:
The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
You must mutate the value that is being pointed to, then callers will see it upon dereference. (As a matter of fact, you don't have to convert to the defined slice type)
func (f *foo) Unmarshal(s string) {
// ...
integers := make([]int, len(numbers))
*f = integers
}
Fixed playground: https://go.dev/play/p/3JayxQMClt-
hi a have this func for get type of value, but i try this and never can get reflect.struct:
type Test struct {
Code int
Name string
}
func main(){
test := getTest()
data, err := getBytes(slice...)
sanitizedFile := bytes.Split(data, []byte("\r\n"))
err = Unmarshal(sanitizedFile[0], &test)
}
func getTest() interface{} {
return Test{}
}
With this code i don't can get the reflecet.struct from v params in Unmarshall func
func Unmarshal(data []byte, v interface{}) error {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rvElem := rv.Elem()
switch rvElem.Kind() {
case reflect.Struct:
// implement me
}
}
return ErrInvalid
}
I would like to know if I can somehow find out if an interface is of type struct or access the values of that struct.
I think the real problem here is illustrated by this quote:
I would like to know if I can somehow find out if an interface is of type struct or access the values of that struct.
An interface value isn't "of type struct". Never! An interface value can contain a value whose type is some structure, but it is not a value of that type. It just contains one. This is similar to the way that a box1 you get from Amazon can contain a corkscrew, but the box is not a corkscrew, ever.
Given a non-nil value of type interface I for some interface type I, you know that you have a value that implements the methods of I. Since {} is the empty set of methods, all types implement it, so given a (still non-nil) value of type interface{}, you have a value that implements no methods. That's not at all useful by itself: it means you can invoke no methods, which means you can't do anything method-like.
But just because you can't do anything method-y doesn't mean you can't do anything at all. Any interface value, regardless of the interface type, can have a type-assertion used on it:
iv := somethingThatReturnsAnInterface()
cv := iv.(struct S) // assert that iv contains a `struct S`
If iv does in fact contain a struct S value—if that's what's inside the box once you open it—then this type-assertion doesn't panic, and cv winds up with the concrete value of type struct S. If panic is undesirable, we can use the cv, ok := iv.(struct S) form, or a type switch. All of these—including the version that panics—work by checking the type of the value inside the interface.
What this—or, more precisely, the way the Go language is defined—tells us is that the interface "box" really holds two things:
a concrete type, and
a concrete value.
Well, that is, unless it holds a <nil, nil> pair, in which case iv == nil is true. Note that the iv == nil test actually tests both parts.
If Go had a syntax for this, we could write something like iv.type and iv.value to get at the two separate parts. But we can't do that. We have to use type assertions, type-switch, or reflect. So, going back to this:
I would like to know if I can somehow find out if an interface is of type struct
we can see that the question itself is just a little malformed. We don't want to know if an interface value has this type. We want to know if a non-nil interface's held value is of this type, as if we could inspect iv.type and iv.value directly.
If you have a limited set of possible types, you can use the type-switch construct, and enumerate all your allowed possiblities:
switch cv := iv.(type) {
case struct S:
// work with cv, which is a struct S
case *struct S:
// work with cv, which is a *struct S
// add more cases as appropriate
}
If you need more generality, instead of doing the above, we end up using the reflect package:
tv := reflect.TypeOf(iv)
or:
vv := reflect.ValueOf(iv)
The latter is actually the more useful form, since vv captures both the iv.type pseudo-field and the iv.value pseudo-field.
As mkopriva notes in a comment, test, in your sample code, has type interface{}, so &test has type *interface{}. In most cases this is not a good idea: you just want to pass the interface{} value directly.
To allow the called function to set the object to a new value, you will want to pass a pointer to the object as the interface value. You do not want to pass a pointer to the interface while having the interface hold the struct "in the box" as it were. You need a reflect.Value on which you can invoke Set(), and to get one, you will need to follow an elem on the reflect.Value that is a pointer to the struct (not one that is a pointer to the interface).
There's a more complete example here on the Go Playground.
1This is partly an allusion to "boxed values" in certain other programming languages (see What is boxing and unboxing and what are the trade offs?), but partly literal. Don't mistake Go's interfaces for Java's boxed values, though: they are not the same at all.
Maybe what you need is type assertion?
t, ok := v.(myStruct)
https://tour.golang.org/methods/15
In any case this code prints "struct":
type tt struct {}
var x tt
var z interface{}
z = x
v := reflect.ValueOf(z).Kind()
fmt.Printf("%v\n", v)
And see this for setting the value of a struct field using reflection:
Using reflect, how do you set the value of a struct field?
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
Problem in Playground: https://play.golang.org/p/UKB8f4qGsM
I have a slice of interfaces, I know for sure which type they have (in reality i don't so I'd have to type switch it, but I left that out for clarity). How can I assign a value to a field in the struct behind the interface? The type assertion seems to take away the reference.
I also tried using pointers, that too doesn't work though, mostly because I can't type assert then (type *inter cannot be type asserted) and when I dereference it, it kinda makes it pointless to even have...
I'm not that experienced in Go, I would appreciate every help I can get.
You can't change the value stored in the interface, you need to use a pointer to the value you want to change:
for i := 0; i < 5; i++ {
slice = append(slice, &b{a: a{name: "Tom"}})
}
for i, _ := range slice {
x := slice[i].(*b)
x.name = "Tim"
}
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{}.