Go is a strictly typed language, which implies that all variables are named elements that are bound to both a value and a type. As you will see, the simplicity and flexibility of its syntax make declaring and initializing variables in Go feel more like a dynamically-typed language.
Before you can use a variable in Go, it must be declared with a named identifier for future reference in the code. The long form of a variable declaration in Go follows the format shown here:
var <identifier list> <type>
The var
keyword is used to declare one or more variable identifiers followed by the type of the variables. The following source code snippet shows an abbreviated program with several variables declared outside of the function main()
:
package main import "fmt" var name, desc string var radius int32 var mass float64 var active bool var satellites []string func main() { name = "Sun" desc = "Star" radius = 685800 mass = 1.989E+30 active = true satellites = []string{ "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", } fmt.Println(name) fmt.Println(desc) fmt.Println("Radius (km)", radius) fmt.Println("Mass (kg)", mass) fmt.Println("Satellites", satellites) }
golang.fyi/ch02/vardec1.go
The previous source code shows several examples of variables being declared with a variety of types. Then the variables are assigned a value inside the function main()
. At first glance, it would appear that these declared variables do not have an assigned value when they are declared. This would contradict our previous assertion that all Go variables are bound to a type and a value.
How can we declare a variable and not bind a value to it? During declaration of a variable, if a value is not provided, Go will automatically bind a default value (or a zero-value) to the variable for proper memory initialization (we see how to do both declaration and initialization in one expression later).
The following table shows Go types and their default zero-values:
Type |
Zero-Value |
|
|
Numeric - Integers: |
0 |
Numeric - Floating point: |
0.0 |
|
false |
|
Each index position has a zero-value corresponding to the array's element type. |
|
An empty |
Other types: Interface, function, channel, slice, map, and pointer |
nil |
As hinted earlier, Go also supports the combination of both variable declaration and initialization as one expression using the following format:
var <identifier list> <type> = <value list or initializer expressions>
This declaration format has the following properties:
The following abbreviated example shows the declaration and initialization combination at work:
var name, desc string = "Earth", "Planet" var radius int32 = 6378 var mass float64 = 5.972E+24 var active bool = true var satellites = []string{ "Moon", }
golang.fyi/ch02/vardec2.go
So far, we have discussed what is called the long form of Go's variable declaration and initialization. To make the language feel closer to its dynamically-typed cousins, the type specification can be omitted, as shown in the following declaration format:
var <identifier list> = <value list or initializer expressions>
During compilation, the compiler infers the type of the variable based on the assigned value or the initializer expression on the right-hand side of the equal sign, as shown in the following example.
var name, desc = "Mars", "Planet" var radius = 6755 var mass = 641693000000000.0 var active = true var satellites = []string{ "Phobos", "Deimos", }
golang.fyi/ch02/vardec3.go
As stated earlier, when a variable is assigned a value, it must receive a type along with that value. When the type of the variable is omitted, the type information is deduced from the assigned value or the returned value of an expression. The following table shows the type that is inferred given a literal value:
Literal value |
Inferred type |
Double- or single-quoted (raw) text:
|
|
Integers:
0
|
|
Decimals:
|
|
Complex numbers:
|
|
Booleans:
|
|
Array values:
|
The |
Map values:
|
The map type defined in the literal value. In this case it is: |
Slice values:
|
The
|
Struct values:
|
A
|
Function values:
|
The function type defined in the function definition literal. In this
|
Go can further reduce the variable declaration syntax using the short variable declaration format. In this format, the declaration loses the var keyword and the type specification, and uses an assignment operator :=
(colon-equal), as shown:
<identifier list> := <value list or initializer expressions>
This is a simple and uncluttered idiom that is commonly used when declaring variables in Go. The following code sample shows usage of the short variable declarations:
func main() { name := "Neptune" desc := "Planet" radius := 24764 mass := 1.024e26 active := true satellites := []string{ "Naiad", "Thalassa", "Despina", "Galatea", "Larissa", "S/2004 N 1", "Proteus", "Triton", "Nereid", "Halimede", "Sao", "Laomedeia", "Neso", "Psamathe", } ... }
golang.fyi/ch02/vardec4.go
Notice the keyword var
and variable types have been omitted in the declaration. Short variable declaration uses the same mechanism to infer the type of the variable discussed earlier.
For convenience, the short form of the variable declaration does come with several restrictions that you should be aware of to avoid confusion:
:=
, declares variable and assign values:=
cannot be used to update a previously declared variableWhile these restrictions may have their justifications rooted in the simplicity of Go's grammar, they are generally viewed as a source of confusion for newcomers to the language. For instance, the colon-equal operator cannot be used with package-level variables assignments. Developers learning Go may find it compelling to use the assignment operator as a way to update a variable, but that would cause a compilation error.
Go uses lexical scoping based on code blocks to determine the visibility of variables within a package. Depending on the location where a variable is declared, within the source text, will determine its scope. As a general rule, a variable is only accessible from within the block where it is declared and visible to all nested sub-blocks.
The following screenshot illustrates the scope of several variables declared within a source text. Each variable declaration is marked with its scope (package
, function
, for
loop, and if...else
block):
As explained earlier, variable visibility works top-down. Variables with package scope, such as mapFile
and numbersFile
, are globally visible to all other elements in the package. Moving down the scope ladder, function-block variables such as data
and err
are visible to all elements in the function and including sub-blocks. Variables i
and b
in the inner for
loop block are only visible within that block. Once the loop is done, i
and b
would go out of scope.
One source of confusion to newcomers to Go is the visibility of package-scoped variables. When a variable is declared at package level (outside of a function or method block), it is globally visible to the entire package, not just to the source file where the variable is declared. This means a package-scoped variable identifier can only be declared once in a group of files that make up a package, a fact that may not be obvious to developers starting out with Go. Refer to Chapter 6, Go Packages and Programs, for details on package organization.
Go's syntax allows the declaration of top-level variables to be grouped together into blocks for greater readability and code organization. The following example shows a rewrite of one of the previous examples using the variable declaration block:
var ( name string = "Earth" desc string = "Planet" radius int32 = 6378 mass float64 = 5.972E+24 active bool = true satellites []string )
golang.fyi/ch02/vardec5.go
3.145.17.18