If I have a struct type A which is used as a pointer (has pointer receivers only, the constructor returns *A, etc.), what is the difference between embedding a struct type B as B versus *B?
That is, what is the difference between
type B struct {...}
type A struct {
B
// ...
}
and
type B struct {...}
type A struct {
*B
// ...
}
For example, is there ever copying of the embedded field?
Edit: I should also mention that the embedded struct B only has pointer receivers.
The zero values of the two structures are different, which can be a significant ergonomic difference.
Consider an embedded type
type B struct {
X int
}
func (b *B) Print() { fmt.Printf("%d\n", b.X) }
If we embed this directly as an object
type AObj struct {
B
}
then the zero value of type AObj includes an embedded object of type B, which also has its zero value, and therefore we can safely
var aObj AObj
aObj.Print() // prints 0
But if we instead embed a pointer
type APtr struct {
*B
}
the zero value of this struct has a nil pointer value, and we can't really use it directly.
var aPtr APtr
aPtr.Print() // panics
Objects get copied in hopefully the way you might expect. If you create a new AObj object, it gets a copy of the embedded B.
aObj2 := aObj
aObj.X = 1
aObj2.Print() // prints 0, because it has a copy
If you create a new APtr object, it gets a copy of the *B, which means it shares the underlying concrete object.
aPtr.B = &B{}
aPtr2 := aPtr
aPtr.X = 1
aPtr2.Print() // prints 1, because both objects point at the same B
Runnable example at https://play.golang.org/p/XmOgegwVFeE
Consider a simple example program. A structAPtr embeds a pointer, a structAVal embeds a struct structB directly:
package main
import "fmt"
type structB struct {
foo int
}
type structAPtr struct {
bar *structB
}
type structAVal struct {
bar structB
}
func main() {
// referencing bStruct
b1 := structB{foo: 12}
aPtr := structAPtr{bar: &b1}
fmt.Println("Before assignment:")
fmt.Printf("aPtr.bar.foo = %d, b.foo = %d\n", aPtr.bar.foo, b1.foo)
aPtr.bar.foo = 42
fmt.Println("After assignment:")
fmt.Printf("aPtr.bar.foo = %d, b.foo = %d\n", aPtr.bar.foo, b1.foo)
// copying bStruct
b2 := structB{foo: 12}
aVal := structAVal{bar: b2}
fmt.Println("Before assignment:")
fmt.Printf("aVal.bar.foo = %d, b.foo = %d\n", aVal.bar.foo, b2.foo)
aVal.bar.foo = 42
fmt.Println("After assignment:")
fmt.Printf("aVal.bar.foo = %d, b.foo = %d\n", aVal.bar.foo, b2.foo)
}
The int structB.foo is used to demonstrate whether structB changes when manipulated inside of structAPtr or structAVal.
This program outputs:
Before assignment:
aPtr.bar.foo = 12, b.foo = 12
After assignment:
aPtr.bar.foo = 42, b.foo = 42 <------------ both changed
Before assignment:
aVal.bar.foo = 12, b.foo = 12
After assignment:
aVal.bar.foo = 42, b.foo = 12 <------------ only assignee changed
Looking at the result shows:
changing the value of the pointer to structB changes structB
changing the value of the copied version structB in structAVal leaves structB unaffected (it is still 5, even after 42 was assigned to aVal)
Edit:
If your structB has only pointer receivers anyways, the intended behavior is probably such that changing structB in strucA updated both of them. That's scenario 1 in my example and requires a pointer for sure. From A Tour of Go:
Methods with pointer receivers can modify the value to which the receiver points [...]. Since methods often need to modify their receiver, pointer receivers are more common than value receivers.
Hope that helps!
Related
This question already has answers here:
Iterate through the fields of a struct in Go
(8 answers)
Closed last month.
e.g. Assuming the interface{} object is a struct {"a":1, "b": "test", c: &AnotherStruct{}}, and we need to iterate the object to get value of each field "a", "b", "c".
I can think of two ways:
use Go reflection directly.
use json.Marshal()/json.Unmarshal() to convert the object to map[string]interface{}, and then iterate over the map to do type assertions, this also calls reflection, however there might be some json library having optimizations inside which might gain better performance, e.g. https://github.com/bytedance/sonic.
I was wondering which one is more efficient and is there any other way to do it?
interface{} is (legacy) go short-hand for "this could be anything". It does not represent an "object" (though it could). From go 1.18 onward the keyword any was introduced as a direct replacement for interface{} (though the latter may continue to be used if you need compatibility with older golang versions).
Here-on I shall use any for brevity.
I'd suggest ignoring efficiency unless/until it becomes a problem you need to solve and instead focus on the clearest and simplest way to achieve what you need, functionally.
It is difficult to be clear about what exactly you are faced with and trying to achieve; your "example" object contains both quoted and unquoted field members so I see four possible scenarios that you may be dealing with:
an any variable holding a value that is of a known formal struct type
an any variable holding a value that is of an anonymous formal struct type
an any variable holding a JSON string
an any variable holding a map[string]any
For scenario's 1 and 2 that would be to marshal to JSON then unmarshal to map[string]any.
For scenario 3 you would cast to string then unmarshal to map[string]any:
For scenario 4 you would directly cast to map[string]any.
I have worked up all of these in a playground for you here: https://go.dev/play/p/cSdUmynTFRp
package main
import (
"encoding/json"
"fmt"
)
type AnotherStruct struct {
X int `json:"x"`
}
type Foo struct {
A int `json:"a"`
B string `json:"b"`
C AnotherStruct `json:"c"`
}
func emit(m map[string]any) {
for k, v := range m {
fmt.Printf(" %s: %s\n", k, v)
}
fmt.Println()
}
func scenario1or2(n int, foo any) map[string]any {
fmt.Printf("scenario %d:\n", n)
j, _ := json.Marshal(foo)
m := map[string]any{}
json.Unmarshal(j, &m)
return m
}
func scenario3(foo any) map[string]any {
fmt.Println("scenario 3")
m := map[string]any{}
json.Unmarshal([]byte(foo.(string)), &m)
return m
}
func scenario4(foo any) map[string]any {
fmt.Println("scenario 4")
return foo.(map[string]any)
}
func main() {
emit(scenario1or2(1, Foo{
A: 1,
B: "test",
C: AnotherStruct{X: 42},
}))
emit(scenario1or2(2, struct {
A int
B string
C AnotherStruct
}{
A: 1,
B: "test",
C: AnotherStruct{
X: 42,
},
}))
emit(scenario3(`{"a":1,"b":"test","c":{"x":42}}`))
emit(scenario4(map[string]any{
"a": 1,
"b": "test",
"c": AnotherStruct{
X: 42,
},
}))
}
If you have scenario 1 and simply want efficient access to the fields (i.e. iterating over potentially unknown fields is not actually required) then you can type-cast directly to the known formal struct type:
// assuming...
type Foo struct {
a int
b string
c *AnotherStruct {
}
}
// and where 'anyfoo' is an `any` holding a Foo
foo := anyfoo.(Foo)
a := foo.a
b := foo.b
c := foo.c
I will like to understand why when I copy a struct value into an interface it behaves like it does. In this code can someone help me understand why when I copy the value from mySlice into foo3 it behaves different than the other copies?
package main
import (
"fmt"
"unsafe"
)
type SliceOfInt []int
// when passing a slice to a method you are passing this data. Lets prove it
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
// Print the header of a slice. Its Data. Len and Cap
func GetHeaderOfSliceOfInt(s unsafe.Pointer) *SliceHeader {
// this header needs to point to &mySlice but compiler will not let us. we have to use unsafe pointers
var header *SliceHeader
pointerToMySlice := s
header = ((*SliceHeader)(pointerToMySlice))
return header
}
func main() {
// On go everything is passed by coping values. When you pass a slice to a function you are passing this:
// reference: https://stackoverflow.com/a/39993797/637142
/*
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
*/
// create a new slice
var mySlice SliceOfInt = make([]int, 0)
mySlice = append(mySlice, 123456789) // append this number to mySlice
// now we have a slice with len:1 and capacity:1. Lets prove it
header := GetHeaderOfSliceOfInt(unsafe.Pointer(&mySlice))
fmt.Println(*header)
// this prints: {824635465728 1 1}
// this means that on memory address 824635465728 there is an array with cap:1 and len:1
// copy that header to someOtherSlice
someOtherSlice := mySlice
header = GetHeaderOfSliceOfInt(unsafe.Pointer(&someOtherSlice))
fmt.Println(*header)
// prints the same value {824635465728 1 1}
// anyways if I go to address 824635465728 on my computer I shoul dbe able to find integer 123456789
pointerToInteger := unsafe.Pointer((*header).Data)
var integerVal *int = ((*int)(pointerToInteger))
fmt.Println(*integerVal)
// if I copy like this, it will print the correct header {824635465728 1 1}
foo1 := mySlice
fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo1)))
// copy like this will also print the correct header {824635465728 1 1}
foo2 := foo1
fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo2)))
// If I copy like this it will print the incorrect header. Why?
var foo3 interface{} = mySlice
fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo3)))
// this last line prints {4746976 824635330392 0}
}
The output of the program is:
{824635465728 1 1}
{824635465728 1 1}
123456789
{824635465728 1 1}
{824635465728 1 1}
{4746976 824635330392 0}
Edit
I know that if I cast foo3 as: foo3.(SliceOfInt) it will work. But why is that?
An interface type, empty or not, is a type in its own right. It has its own memory representation and it is a legitimate member of Go's type system.
An interface value, and the value wrapped in that interface, are not one and the same.
The variables foo1 and foo2 have the same type and value as the mySlice variable. But the variable foo3 has a different type, therefore also a different value. And yes, the dynamic type and value are the same as mySlice but the static type and value are not.
An interface value is NOT represented in memory by a structure that's compatible with the three-field SliceHeader and therefore it is wrong, not only semantically, to try to take the slice header off of an interface value. Instead, an interface value is represented by a 2-field structure (that's why in your attempt the third field is 0). The first field points to the type information of the wrapped value, the second field points to the data of the wrapped value.
Something like this:
type iface struct {
typ uintptr
data uintptr
}
And you can test this by doing this:
x := (*iface)(unsafe.Pointer(&foo3))
s := (*SliceHeader)(unsafe.Pointer(x.data))
fmt.Printf("%+v\n", x)
fmt.Printf("%+v\n", s)
https://go.dev/play/p/2KUgCU8h7O7
Also, consider reading this: https://research.swtch.com/interfaces.
I am little consfused about value type struct wrapped by pointer type struct.
Example:
package main
import (
"fmt"
)
type A struct {
id int
B
}
func (a *A) setId(val int) {
a.id = val
}
type B struct {
name string
}
func (b B) setNameViaValue(val string) {
b.name = val
}
func (b *B) setNameViaPointer(val string) {
b.name = val
}
func main() {
a := new(A)
a.setId(1)
a.setNameViaValue("valuename")
fmt.Println(a)
a.setNameViaPointer("pointername")
fmt.Println(a)
}
I would expect that referencing through pointer type A struct(which addresses concrete memory) that wraps B value type struct will set inner value no matter what kind of refence to B is used (B/*B). This is also related to type definition. Can anyone also explain what is different when I define it like this? Is there any usecase scenario?
type A struct {
id int
*B
}
Why doesn't setNameViaValue end up setting the name
If you declare a method with a value (non-pointer) receiver, then that method cannot "modify" the receiver cause it will actually receive a copy.
That's why the "name" is not set as you expected with the setNameViaValue method.
If you want to be able to set the name of B in that way, only setNameViaPointer is an option.
You can read more about the differences between method and value receivers here:
https://tour.golang.org/methods/8
Why can you actually invoke the inner struct methods on the outer struct
That's because you "embedded" the inner struct in the outer one.
When you include a struct type name without giving it a field name, then all of the "inner" struct methods and fields are "promoted" to the outer one.
That means you can call a.setNameViaValue and it will be equivalent to doing a.B.setNameViaValue.
Is there any difference if I embedded as a pointer
If you define A this way:
type A struct {
id int
*B
}
Then:
The "setNameViaValue" will still not work (that's only related to the method being defined over a value instead of a pointer receiver, it has nothing to do with how A references B).
You will need to initialize B explicitly when creating an A object, otherwise *B will end up being nil. (if you reference it as a value, it will be initialized as an empty B)
You can change what *B points to later on (if it was a value, then it will always reference the same "value")
I am new to Go and have some experience in C. Now the thing which confuses me the most is why, in the code below, we need to dereference str to modify value but not chk.j.
What additional thing is happening in here in the case of structs?
type test struct {
i int
j string
}
func main() {
str := new(string)
*str = "Need Astrik"
chk := new(test)
chk.i = 5
chk.j = "Confused"
fmt.Println("printing", chk.i, chk.j, *str)
}
See Selectors section in the spec:
Selectors automatically dereference pointers to structs. If x is a pointer to a struct,x.y is shorthand for (*x).y; if the field y is also a pointer to a struct, x.y.z is shorthand for (*(*x).y).z, and so on. If x contains an anonymous field of type *A, where A is also a struct type, x.f is shorthand for (*x.A).f.
In summary: pointer members of structs are dereferenced automatically.
For assignments there's no such shortcut, so assigning pointees is the same as in C:
*p = value
In the case of struct x with a member y that is a pointer you want to assign its target a value to:
*x.y = value
In case the x is a pointer to a struct, the expression above translates to
*((*x).y) = value
new creates a pointer. If you want to assign something to what the pointer is pointing to, you need to dereference it. If you didn't create your values with new, you wouldn't need to dereference any pointers:
//without magic := so you actually see the types of things
package main
import "fmt"
func main(){
var s string = "Hello World"
s = "hello"
var sp (*string) = &s
fmt.Println(s) //hello
fmt.Println(*sp) //hello
*sp = "world"
fmt.Println(s) //world
fmt.Println(*sp) //world
}
You don't need to dereference your test chk because . can behave like both -> and . from C depending on whether you use it on a struct or a pointer to a struct.
With a type:
type A struct {
B int, C *int
}
How do I initialise a pointer member to a non-zero value inline, without creating temporaries?
a := A{
B: 42,
C: ?,
}
For the specific example you've given you are limited in what you can do without introducing additional statements.
If you want C to point at an initialised integer variable, you will need an additional statement to define that variable since you can't take the address of an integer literal (i.e. &42 would be an error).
If you just want to initialise C as a pointer to a new zero value, you are in luck though and can set it to new(int).
If you were instead dealing with a different type that had an initialiser syntax, you would also been in luck. For example, if C was a pointer to a structure, you could initialise it to &TheStruct{...}.
If none of these are appropriate, and you are really only after code clarity for initialising *int variables, a helper function might fit your requirements. For example:
func makeIntPointer(v int) *int {
return &v
}
package main
import "fmt"
type A struct {
B int
C *int
}
func newint(i int) *int{
return &i
}
func main() {
c := newint(5)
a := &A{
B: 42,
C: c,
}
fmt.Printf(" %v" , *a.C)
fmt.Printf(" %#v" , a.C)
}
http://play.golang.org/p/s0HIMHoMRo