Showing posts with label Pointers. Show all posts
Showing posts with label Pointers. Show all posts

Tuesday, March 2, 2021

Pointers in Go

Understand all about declaring and using pointers in Go

If you're coming from Python, Java, JavaScript, C# and others, talking pointers may scare you. But fear not! Go's approach to pointers is very elegant and definitely very easy to understand.

Variables

We cannot talk pointers without understanding variables. Every variable you declare in Go (or any programming language for that matter) is essentially a way to identify a block of memory that contains a value assigned to it.

There are multiple ways to declare variables in Go. For example:

package main

import "fmt"

func main() {
     var name = "John Smith"
     var email string = "john@smith.com"
     fmt.Printf("Name: %v, Email: %v", name, email)
}

We could have used the & operator to access the memory addresses of our variables:

fmt.Printf("&name: %v, &email: %v", &name, &email)
&name: 0xc00010a040, &email: 0xc00010a050

Pointers

But what about pointers? Pointers are nothing more than variables that hold the memory address of a value. In other words, the location at which a value is stored. In Go, the * character is used to either declare and read the value of a pointer For example, The type *T is a pointer to a T value.

The zero value for an unassigned pointer is always nil.

Declaring Pointers

To declare pointers, use the * character preceding its type. Like variables pointers have to be declared before they are accessed following this syntax:

var myVar *type

For example:

var p *int // declares a pointer to int

Assigning values to pointers

To assign values to pointers, you should point it to the address of another variable. That's done by using the & operator we saw previously:

i := 22 // assigns 22 to i (i is an int)
p = &i  // makes p point to the address of i

Reading pointer values

To read the values of our pointers we use the * operator:

fmt.Println(*p) // read i through the pointer p
What you see above is called "dereferencing" or "indirecting".

Nil Pointers

Since in Go you cannot declare and set a value to pointers, by default, every unassigned pointer has its zero values set to nil. The nil pointer is a constant with a value of zero as we can see in the example below:

q *int
fmt.Printf("Q: %v %x", q, q)
Q: <nil> 0

But what happens if we try to access its value before we use it? Yes, an error:

fmt.Println("Q: %v", *q)

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4990a3]

Checking if a pointer is assigned

To check if a pointer has been assigned to, you could compare it to nil. True means your pointer is assigned to a memory address and it's safe to access its value:

fmt.Println("Is p assigned?", p != nil)
Is p assigned? true

Comparing pointers

Can we compare pointers? Definitely, by using the & operator:

var x, y int
fmt.Println(&x == &x, &x == &y, &x == nil)
true false false

When use Pointers

So when should you use pointers? Since pointers allow accessing variables indirectly you may think that whenever you need to access your values. But the rule of thumb is that you should use pointers for sharing data - whenever you want an external function to be able to modify your data.

Limitations of Pointers

If you're coming from C, there's one important detail. Go unlike C, Go has no pointer arithmetic. 

Conclusion

On this post we learned about pointers in Go. If you're coming from Python, Java, JavaScript, C# and others, talking pointers may scare you. but fear not! Go's approach to pointers is very elegant and definitely very easy to understand.

Remember, that pointers make your code a little less legible so use them whenever you need to share some value.

See Also

Tuesday, December 22, 2020

The new function in Go

Know everything about the new function in Go, especially when and how to use it.

Apart from the standard way to declare variables, Go offers another way to declare variables via the built-in function new function. Its format is:

myVar := new(myType)

Can you guess what's the type for myVar on the example above? If you guessed *myType, you got it right: the new function returns a pointer to the specified type. So let's understand a little more about it.

A deeper look

Because new always returns a pointer to the specified type, it's fair to say that as with pointers, every call to the new  function will create an unnamed variable, initialize it its zero value and return its address, a pointer to the specified type. For example:

package main

import (
"fmt"
)

func main() {
p := new(int)
fmt.Printf("p: %v, *p: %v, &p: %v", p, *p, &p)
}


p: 0xc000100010, *p: 0, &p: 0xc000102018

When to use the new function?

And when should we use new?

The main reason to use new is that you don't need to declare a new variable just to assign values to your pointers, with the tradeoff that your code becomes less readable.

Think of it as a convenience to abbreviate the three-step process of declaring and assigning values to pointers:

// this block
i := 22
var p *int
p = &i

// could be replaced by this
p := new(int)
*p = 22

Conclusion

On this article we learned about the new function in Go. One of the advantages of using new is that you don't need to declare a dummy variable to assign your pointers to it. But since new returns a pointer to the specified type, it may be confusing for new users of the language. For that reason, the new function is not very used but definitely, it's worth knowing.

See Also

Any comment about this page? Please contact us on Twitter

Featured Article

Pointers in Go

Understand all about declaring and using pointers in Go If you're coming from Python, Java, JavaScript, C# and others, tal...

Popular Posts