I am still learning go and need a hand to clear my head.
Following program output Power value as 1 in each Println. I was expecting 1 as first output and 2 as second output.
My assumption was the Change func overwrite the address of s with anew address and this change will reflect back to the caller (main func). In such case, the original address would be pointing to newly created address when it call the second Println.
My assumption is wrong but I can't figure out why.
package main
import (
"fmt"
)
type Pod struct{
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
s = &Pod{2}
}
Code
To explore further on what happens under cover, I did tried to print addresses this time and it looks like below;
import (
"fmt"
)
type Pod struct{
Power int
}
func main() {
pod := &Pod{ 1}
fmt.Println(&pod) //0xc04202c020
Change(pod)
fmt.Println(&pod) //0xc04202c020
}
func Change(s *Pod) {
fmt.Println(&s) //0xc04202c030 ( I was expecting 0xc04202c020 here)
s = &Pod{ 2}
fmt.Println(&s) //0xc04202c030
}
It's because when you pass arguments to functions etc, they are always passed by value.
In other words, even though you are accepting a pointer in the function parameter, the address of the struct will be copied.
Then when you assign to s to try and change the address it only changes that local copy, not the one outside the function.
To change the address from within the function you would need to pass in a pointer pointer, then assign to the dereferenced s, for example:
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(&pod)
fmt.Println(pod.Power)
}
func Change(s **Pod) {
*s = &Pod{2}
}
In this case a copy of an address is still being passed into the function, but because it's a pointer to a pointer it means that when you dereference s as *s you will get the address of the struct outside of the function. This means if you assign to *s you can change the address of the pointer outside the function.
Of course, like Andy Schweig says, you probably wouldn't really want to do that though, and would probably just change individual fields as needed with the normal pointer version of the function.
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
s.Power = 2
}
This works because when you type s.Power = 2 Go will actually do something like (*s).Power = 2 for you. So it automatically dereferences s for you which gives you the actual Pod struct to work with.
You can't do *s = &Pod{2} in this normal pointer example because in that case *s will actually equal type Pod, not *Pod.
Because of that if you want to use the &Pod{2} syntax to assign an address you need to pass a pointer to the pointer. In the case of s **Pod the dereferenced *s will point to the address of the Pod instead of the actual Pod, so *s will be of type *Pod which allows you to assign &Pod{2}.
Having said all of that, a **Pod is only required if you want to assign an address with the &Pod{2} syntax.
If you don't need to use the &Pod{2} syntax you can just dereference s and assign with a normal Pod{2}.
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
*s = Pod{2}
}
This also works, because now s is a copy of an address, and when you dereference you get to the value outside the function which is type Pod, not *Pod.
That means you can just assign to it by removing the &.
Basically if you use & it means you want to assign an address rather than the actual value.
I hope this explanation isn't too confusing. I explained using a **Pod because I thought you wanted to use the &Pod{2} syntax rather than Pod{2}, but if that's not the case then my s.Power = 2 or *s = Pod{2} examples may make more sense.
Changing the value of a parameter to a function inside the function never has an effect on the parameter passed by the caller. All parameters are passed by value. If you want to change the value of Power inside the object pointed to by s (pod in the caller), use s.Power = 2. If you actually want to set the pointer variable in the caller to a different Pod object, you need to declare the parameter to Change as s **pos, change the assignment in the function to *s = &Pod{2}, and call Change(&pod). That's probably not what you want to do, though.
Related
I'm having trouble understanding why golang returns a different memory address on what appears to be the same struct (maybe it's not, perhaps it copies with the same values to another memory address?).
Here's the code
package main
import (
"fmt"
)
type Creature struct {
Name string
isAlive bool
}
func foo() Creature {
myCreature := Creature{Name: "dino", isAlive: true}
fmt.Printf("%p\n", &myCreature)
fmt.Println(myCreature)
return myCreature
}
func main() {
myCreat := foo()
fmt.Printf("%p\n", &myCreat)
fmt.Println(myCreat)
}
The output of the code is the following
0xc000004090
{dino true}
0xc000004078
{dino true}
As you can see, the memory addresses are different. Why?
Should I instead return a memory address?
I'm having trouble understanding why golang returns a different memory address on what appears to be the same struct (maybe it's not, perhaps it copies with the same values to another memory address?).
You didn't return a memory address, you returned a struct.
As you can see, the memory addresses are different.
Because you returned a struct and it was copied to a new one.
Why? Should I instead return a memory address?
Yes, if you want a pointer then return that.
package main
import (
"fmt"
)
type Creature struct {
Name string
isAlive bool
}
func foo() *Creature {
myCreature := Creature{Name: "dino", isAlive: true}
fmt.Printf("%p\n", &myCreature)
fmt.Println(myCreature)
return &myCreature
}
func main() {
myCreat := foo()
fmt.Printf("%p\n", myCreat)
fmt.Println(*myCreat)
}
Playground
The rule in Go is that you only use pointers when you actually need them, when you have to modify a struct's values or something. You should not use pointers because you think it might be more efficient. The memory optimiser can do its work more efficiently if you don't force it to do things one way or another.
See https://medium.com/#vCabbage/go-are-pointers-a-performance-optimization-a95840d3ef85, https://betterprogramming.pub/why-you-should-avoid-pointers-in-go-36724365a2a7, and many more articles.
I'd like to iterate over the fields in a struct and prompt for string values to string fields, doing this recursively for fields that are pointers to structs.
Currently this is what I've tried, but I get an error when trying to set this value in the pointer's string field.
package main
import (
"fmt"
"reflect"
)
type Table struct {
PK *Field
}
type Field struct {
Name string
}
func main() {
PopulateStruct(&Table{})
}
func PopulateStruct(a interface{}) interface {} {
typeOf := reflect.TypeOf(a)
valueOf := reflect.ValueOf(a)
for i := 0; i < typeOf.Elem().NumField(); i++ {
switch typeOf.Elem().Field(i).Type.Kind() {
case reflect.String:
fmt.Print(typeOf.Elem().Field(i).Name)
var s string
fmt.Scanf("%s", &s)
valueOf.Elem().Field(i).SetString(s)
case reflect.Ptr:
ptr := reflect.New(valueOf.Elem().Field(i).Type())
PopulateStruct(ptr.Elem().Interface())
valueOf.Elem().Field(i).Set(ptr)
}
}
}
Expecting the return value to include an initialised struct with the pointers string field set.
Getting an error when setting the pointer's string field.
panic: reflect: call of reflect.Value.Field on zero Value
I dropped your code as-is into the Go Playground and it doesn't build because PopulateStruct is declared as returning interface{} but does not actually return anything. Removing the declared return type produces the panic you mention.
This is because at entry to the outer PopulateStruct call, you have a valid pointer, pointing to a zero-valued Table. A zero-valued Table has one element: a nil pointer in it of type *Field. Your loop therefore runs once and finds a reflect.Ptr, as you expected. Adding more diagnostic print messages helps see what's happening:
fmt.Printf("PopulateStruct: I have typeOf=%v, valueOf=%v\n", typeOf, valueOf)
for i := 0; i < typeOf.Elem().NumField(); i++ {
switch typeOf.Elem().Field(i).Type.Kind() {
// ... snipped some code ...
case reflect.Ptr:
ptr := reflect.New(valueOf.Elem().Field(i).Type())
fmt.Println("after allocating ptr, we have:", ptr.Type(), ptr,
"but its Elem is:", ptr.Elem().Type(), ptr.Elem())
This prints:
PopulateStruct: I have typeOf=*main.Table, valueOf=&{<nil>}
after allocating ptr, we have: **main.Field 0x40c138 but its Elem is: *main.Field <nil>
Given the way PopulateStruct itself is constructed, we must actually allocate a real Field instance now, before calling PopulateStruct. We can do this with:
p2 := ptr.Elem()
ptr.Elem().Set(reflect.New(p2.Type().Elem()))
(code borrowed from json.Unmarshal). Now we can fill in this Field, which has one field named Name of type String.
The overall strategy here is not that great, in my opinion: filling-in probably should take a generic pointer, not specifically a pointer-to-struct pointer. You can then emulate the indirect function in the json unmarshaller. However, the addition of these two lines—creating the target object and making the allocated pointer point to it—suffices to make your existing code run.
(Alternatively, you could just create and return a whole instance from scratch, in which case all you need is the type—but I'm assuming you have a pattern in which only some fields are nil.)
Here's the complete Go Playground example. I made a few other changes as there's nothing to scan from when using the playground.
I am passing a pointer to a string, to a method which takes an interface (I have multiple versions of the method, with different receivers, so I am trying to work with empty interfaces, so that I don't end up with a ton of boilerplate madness. Essentially, I want to populate the string with the first value in the slice. I am able to see the value get populated inside the function, but then for some reason, in my application which calls it, tha value doesn't change. I suspect this is some kind of pointer arithmetic problem, but could really use some help!
I have the following interface :
type HeadInterface interface{
Head(interface{})
}
And then I have the following functions :
func Head(slice HeadInterface, result interface{}){
slice.Head(result)
}
func (slice StringSlice) Head(result interface{}){
result = reflect.ValueOf(slice[0])
fmt.Println(result)
}
and... here is my call to the function from an application which calls the mehtod...
func main(){
test := x.StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
x.Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println(result)
}
*NOTE : I am aware that getting the first element doesn't need to be this complicated, and could be slice[0] as a straight assertion, but this is more of an exercise in reusable code, and also in trying to get a grasp of pointers, so please don't point out that solution - I would get much more use out of a solution to my actual problem here * :)
As you said in your NOTE, I'm pretty sure this doesn't have to be this complicated, but to make it work in your context:
package main
import (
"fmt"
"reflect"
)
type HeadInterface interface {
Head(interface{})
}
func Head(slice HeadInterface, result interface{}) {
slice.Head(result)
}
type StringSlice []string
func (slice StringSlice) Head(result interface{}) {
switch result := result.(type) {
case *string:
*result = reflect.ValueOf(slice[0]).String()
fmt.Println("inside Head:", *result)
default:
panic("can't handle this type!")
}
}
func main() {
test := StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println("outside:", result)
}
The hard part about working with interface{} is that it's hard to be specific about a type's behavior given that interface{} is the most un-specific type. To modify a variable that you pass as a pointer to a function, you have to use the asterisk (dereference) (for example *result) on the variable in order to change the value it points to, not the pointer itself. But to use the asterisk, you have to know it's actually a pointer (something interface{} doesn't tell you) so that's why I used the type switch to be sure it's a pointer to a string.
I want to compare 2 instance of the same struct to find out if it is equal, and got two different result.
comment the code // fmt.Println("%#v\n", a), the program output is "Equal"
Use the fmt to print variable "a", then I got the output "Not Equal"
Please help me to find out Why???
I use golang 1.2.1
package main
import (
"fmt"
)
type example struct {
}
func init() {
_ = fmt.Printf
}
func main() {
a := new(example)
b := new(example)
// fmt.Println("%#v\n", a)
if a == b {
println("Equals")
} else {
println("Not Equals")
}
}
There are several aspects involved here:
You generally cannot compare the value of a struct by comparing the pointers: a and b are pointers to example not instances of example. a==b compares the pointers (i.e. the memory address) not the values.
Unfortunately your example is the empty struct struct{} and everything is different for the one and only empty struct in the sense that it does not really exist as it occupies no space and thus all different struct {} may (or may not) have the same address.
All this has nothing to do with calling fmt.Println. The special behavior of the empty struct just manifests itself through the reflection done by fmt.Println.
Just do not use struct {} to test how any real struct would behave.
They seem to be the same:
package main
import "fmt"
type S struct {
i int
}
func main() {
var s1 *S = new(S)
fmt.Println(s1)
var s2 *S = &S{}
fmt.Println(s2) // Prints the same thing.
}
Update:
Hm. I just realized that there's no obvious way to initialize S.i using new. Is there a way to do that? new(S{i:1}) does not seem to work :/
From Effective Go:
As a limiting case, if a composite literal contains no fields at all, it creates a zero value for the type. The expressions new(File) and &File{} are equivalent.
Not only do they give the same resulting value, but if we allocate something both ways and look at their values...
// Adapted from http://tour.golang.org/#30
package main
import "fmt"
type Vertex struct {
X, Y int
}
func main() {
v := &Vertex{}
v2 := new(Vertex)
fmt.Printf("%p %p", v, v2)
}
...we'll see that they are in fact allocated in consecutive memory slots. Typical output: 0x10328100 0x10328108. I'm not sure if this is an implementation detail or part of the specification, but it does demonstrate that they're both being allocated from the same pool.
Play around with the code here.
As for initializing with new, according to the language spec: The built-in function new takes a type T and returns a value of type *T. The memory [pointed to] is initialized as described in the section on initial values. Because functions in go can't be overloaded, and this isn't a variadic function, there's no way to pass in any initialization data. Instead, go will initialize it with whatever version of 0 makes sense for the type and any member fields, as appropriate.
Case 1: package main
import (
"fmt"
)
type Drink struct {
Name string
Flavour string
}
func main() {
a := new(Drink)
a.Name = "Maaza"
a.Flavour = "Mango"
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Frooti"
fmt.Println(a.Name)
}//This will output Frooti for a.Name, even though the addresses for a and b are different.
Case 2:
package main
import (
"fmt"
)
type Drink struct {
Name string
Flavour string
}
func main() {
a := Drink{
Name: "Maaza",
Flavour: "Mango",
}
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Froti"
fmt.Println(a.Name)
}//This will output Maaza for a.Name. To get Frooti in this case assign b:=&a.