Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rule for Go Pointers, References, Dereferencing:

I am new to GoLang, coming from the Delphi, C++ world - admittedly very excited about this language, which I think is destined to become "the next big thing".

I am trying to get a handle around how the Go parser and compiler handle pointers and references - can't seem to find any place where some clear rules are laid out.

In the below code sample for example, the return type *list.List and the local variable l are pointer types and require the pointer symbol * in their declarations, but they don't have to be dereferenced in use: l.PushBack(i). But in this same code the input parameter value *int64 is declared as a pointer and has to be dereferenced to be used properly: var i int64 = *value / 2

I assume that this is because list.List is a reference type, so the dereferencing is implicit when used, while int64 is a value type and must be handled just as any pointer to a value type, as in C++ for example: It must be dereferenced.

What is confusing to me is that even though *list.List has to be declared as a pointer type using *, when using the list instance, dereferencing is not required. This had me quite confused initially. Is that "just the way it is", or am I missing something?

Sample:

func GetFactors(value *int64) *list.List {

    l := list.New()

    l.PushBack(*value)

    var i int64 = *value / 2

    for ; i > 1; i-- {

        if *value%i == 0 {

            l.PushBack(i)

        }
    }

    return l

}
like image 520
Vector Avatar asked Dec 31 '13 00:12

Vector


Video Answer


1 Answers

All of the methods for a List have *List receivers: (http://golang.org/pkg/container/list/)

func (l *List) Back() *Element
func (l *List) Front() *Element
func (l *List) Init() *List
...
func (l *List) Remove(e *Element) interface{}

In your example l is of type *List, so there's no need to dereference them.

Suppose, instead, that you had something like this:

type A struct{}
func (a  A) X() {
    fmt.Println("X")
}
func (a *A) Y() {
    fmt.Println("Y")
}

You are allowed to write:

a := A{}
a.X()
a.Y() // == (&a).Y()

Or you can do the following:

a := &A{}
a.X() // same like == (*a).X()
a.Y()

But it only works for method receivers. Go will not automatically convert function arguments. Given these functions:

func A(x *int) {
    fmt.Println(*x)
}
func B(y int) {
    fmt.Println(y)
}

This is invalid:

A(5)

You have to do this:

var x int 
A(&x)

This is also invalid:

var y *int
B(y)

You have to do this:

B(*y)

Unlike C# or Java, when it comes to structs, Go does not make a distinction between reference and value types. A *List is a pointer, a List is not. Modifying a field on a List only modifies the local copy. Modifying a field on a *List modifies all "copies". (cause they aren't copies... they all point to the same thing in memory)

There are types which seem to hide the underlying pointer (like a slice contains a pointer to an array), but Go is always pass by value.

like image 99
Caleb Avatar answered Sep 16 '22 12:09

Caleb