Declaring Variables
From: variables.go
4 var i int 5 var Θ float32 6 var explicitly, typed, pointers *complex128 7 int_pointer := &i 8 another_int_pointer := new(int) 9 generic_channel := make(chan interface{})
Variables are declared with the var keyword, followed by the variable name, and finally by the type. The existence of a specific keyword for variable declarations makes it easy to differentiate them from other types of statements.
Writing the type at the end looks weird to people familiar with C-family languages, but it makes sense when you read the code. A (typed) variable declaration is an instruction saying, for example, “declare the variable foo to have the type int.”
One of the variables declared at the start of this section uses θ (theta) as a variable name. Go permits identifiers to start with any symbols that Unicode classes as letters. This can sometimes be very useful, such as if variable names are mathematical quantities. Don’t abuse it, though: the person maintaining your code will not thank you if you use characters that he can’t type on his keyboard for frequently used variables.
A declaration statement may declare multiple variables, but they all have the same type. In C, some may have the type that is written at the start of the declaration, some may be pointers to that type, some may be pointers to pointers to that type, and so on. The form used by Go is far less prone to ambiguity.
You will rarely use the long form of declarations. One of the key ideas in writing good code is the principle of minimum scope. This means that the scope of a variable—the lexical region where it is valid—should be as small as possible for the variable’s lifetime. One corollary of this is that variables should be declared immediately before their first use and initialized as part of their declaration.
Go provides a shorthand syntax, the := initialization operator, which does this. Using this notation, you can declare and initialize a variable in a single statement. More importantly, you avoid the need to declare a type for the variable: the type of the variable is the type of the expression used to initialize it.
The example at the start of this section shows both kinds of declaration. It also introduces Go’s syntax for pointers. The variable int_pointer is initialized using the address-of operator (&). This should be familiar to C programmers: it returns the address in memory of an object. The returned value, however, is more similar to a Java reference than a C pointer. You can’t perform arithmetic using Go pointers, nor use them interchangeably with arrays. As with Java references, you can pass Go pointers around without having to worry about when the underlying object will be deallocated. It will automatically be freed when the last reference is destroyed. Unlike Java references, you can make pointers to primitive types, not just to structures (Go’s equivalent of objects).
In this example, you could return int_pointer from this function without any problems. This may seem strange to C programmers, because it points to a variable declared locally. The Go compiler will try to allocate i on the stack, but that’s just an implementation detail. If its address is taken and it is returned from the function then it will be allocated on the heap instead.
This example creates another integer pointer, in a different way. The new() built-in function creates a new integer and returns a pointer to it. This is semantically equivalent to declaring an integer variable and then taking its address. Neither guarantees how the underlying storage will be allocated. You can pass any type to new(), but it is not the standard way of allocating everything.
Go includes three special types, which we’ll look at in a lot more detail later in this book: slices, maps, and channels. These are reference types, meaning that you always access them via a reference. If you assign one map-typed variable to another, then you will have two variables referring to the same map. In contrast, if you assign one integer-typed variable to another, then you will have two variables with the same value, but modifying one will not affect the other.
Instances of reference types in Go are created with the make() built-in function. This is similar to new(), but also performs initialization of the built-in types. Values returned by new() are simply zeroed. They are not guaranteed to be immediately useful, although good style suggests that they should be.