Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to another struct by value or by pointer

What difference there is when you access to another struct by value or by a pointer?
When should be used each one of them?

type foo_ struct {
    st uint8
    nd uint8
}

type bar struct {
    rd  uint8
    foo foo_
}

type barP struct {
    rd  uint8
    foo *foo_
}
like image 982
user316368 Avatar asked May 02 '10 18:05

user316368


People also ask

Should I use a pointer instead of a copy of my struct?

For many Go developers, the systematic use of pointers to share structs instead of the copy itself seems the best option in terms of performance.

Is struct pass by value or reference?

A struct is a value type, so it's always passed as a value. A value can either be a reference type (object) or a value type (struct). What's passed around is always a value; for a reference type you pass the value of the reference to it, for a value type you pass the value itself.

How do you access values of a struct using pointers?

To access members of a structure using pointers, we use the -> operator. In this example, the address of person1 is stored in the personPtr pointer using personPtr = &person1; .

When would you use a pointer to a struct?

Pointer to structure holds the add of the entire structure. It is used to create complex data structures such as linked lists, trees, graphs and so on. The members of the structure can be accessed using a special operator called as an arrow operator ( -> ).


3 Answers

If you declare or allocate a variable of type bar, you reserve and initialize to zero memory for both rd uint8 and foo foo_. There is always one variable of type foo_ embedded in a variable of type bar.

var b bar  // declare b

If you declare or allocate a variable of type barP, you reserve and initialize to zero memory for both rd uint8 and foo *foo_. A zero value pointer is a nil pointer. No variable of type foo_ is allocated; you must do that separately. There is either zero (foo == nil) or one variable of type foo_ pointed to by a variable of type barP. A variable of type barP may point to the same variable of type foo_ as other variables of type barP, sharing the same copy of the variable of type foo_. A change to a shared copy is seen by all variables that point to it.

var bp barP         // declare bp
bp.foo = new(foo_)  // allocate bp.foo

Which one to use depends on the properties of type bar versus type barP. Which type more closely reflects the problem that you are trying to solve?

For example, consider this invoice problem. We always have a billing address; we are always going to ask for our money. However, we often ship to the billing address, but not always. If the shipping address is nil, use the billing address. Otherwise, use a separate shipping address. We have two warehouses, and we always ship from one or the other. We can share the two warehouse locations. Since we don't send an invoice until the order is shipped from the warehouse, the warehouse location will never be nil.

type address struct {
    street string
    city   string
}

type warehouse struct {
    address string
}

type invoice struct {
    name      string
    billing   address
    shipping  *address
    warehouse *warehouse
}
like image 166
peterSO Avatar answered Sep 28 '22 08:09

peterSO


The answer is largely independent of language - the equivalent in C has the same issues.

When you have an embedded value (as in bar), then your structure is big enough to hold the complete sub-structure and the other part.

When you have a pointer to a value (as in barP), then a number of structures of type barP may share the same foo. When any of the barP modifies a part of the foo it points to, it affects all the other barP structures that point to the same place. Also, as the commentary suggests, you have to manage two separate objects - the barP and the foo as against one with the plain bar type.

In some languages, you would have to worry about dangling pointers and uninitialized values etc; Go is garbage collected and generally more type-safe than other languages.

So, use a pointer when you want multiple barP objects to share the same foo object; otherwise, use an explicit member object, rather than a pointer to an object.

like image 24
Jonathan Leffler Avatar answered Sep 28 '22 08:09

Jonathan Leffler


The Golang FAQ now summarizes the difference between:

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value

First, and most important, does the method need to modify the receiver?
If it does, the receiver must be a pointer. (Slices and maps are reference types, so their story is a little more subtle, but for instance to change the length of a slice in a method the receiver must still be a pointer.)
In the examples above, if pointerMethod modifies the fields of s, the caller will see those changes, but valueMethod is called with a copy of the caller's argument (that's the definition of passing a value), so changes it makes will be invisible to the caller.
By the way, pointer receivers are identical to the situation in Java, although in Java the pointers are hidden under the covers; it's Go's value receivers that are unusual.

Second is the consideration of efficiency. If the receiver is large, a big struct for instance, it will be much cheaper to use a pointer receiver.

(This efficiency point is also illustrated in "Memory, variables in memory, and pointers ")

Next is consistency. If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used. See the section on method sets for details.

like image 41
VonC Avatar answered Sep 28 '22 07:09

VonC