In programming, variables are placeholders holding values. A variable in Go is associated with four elements: a keyword, a name, a type and a value. Variables are particularly useful to hold values we might want to use throughout our program, and to avoid using literal values everywhere.
Asides from variables, Go offers the possibility to use constants. Constants also have the ability to hold values. However, the value associated to a constant cannot be changed once it has been assigned, as opposed to variables.
In this tutorial, we will also go through the concept of scope. A scope defines the boundaries within which our variables and constants can be accessed. We are going to see that Go is characterised by a lexical scope, defined within curly brackets. Go is also characterised by a package scope, a feature that we will study in a later tutorial when we speak about functions.
As mentioned in the introduction, a variable is characterised by four elements: a keyword, a name, a type and a value.
In Go, a variable definition starts with the var keyword.
Following the var keyword, a name for this variable must be chosen. In Go, there is an idiomatic set of rules that should be followed in order to correctly name a variable. Names should always start with a letter. The subsequent characters can either be other letters, numbers or underscore. In addition, the naming convention dictates the usage of camel case for compound names (eg. minNumber).
As Go is a statically-typed language, each variable needs to be assigned a data type, and that type cannot be changed throughout the lifetime of this variable. Those types can be any of those we have seen so far (string, number, boolean), or any other more complex types we will see later on.
Finally, our variable needs to be assigned a value. This value can be a literal value (for example, 1 or "Hello, World!"), but any another variable or constant can be assigned as a value too. The value assignment is independent from the variable declaration (where we define the keyword, the name and the type). Therefore, this last step can actually be performed later on in the program, after the variable declaration.
Programmatically, a variable is defined as followed.
var hello string = "Hello, variable!"
As you can see, we have used our var keyword, the name of our variable is hello, the type of our variable is a string and the value is "Hello, variable!".
As mentioned earlier, we could have divided the declaration and the value assignment into two separated lines.
var hello string hello = "Hello, variable!" /* We use the name of our variable to assign a value to it, using the = sign */
As the name suggests, we can change the value assigned to our variable at any point in our program (but not its type). To do so, we just need to reassign a value to that variable.
var x string = "Original value" x = "Substituted value" fmt.Println(x) // This will print "Substituted value" to the console
If we run this program, it will output "Substituted value" to the console. It is indeed the value we have reassigned to our variable x in the second line of our program.
In fact, there are shorter ways we can use to define a variable. As a convention, those shorter versions should be used whenever it is possible.
Firstly, we could remove the type from our declaration. Go’s compiler is indeed capable of inferring the type of a variable by looking at the value being assigned. This however only works if we declare and assign a value to our variable in the same line. The program wouldn’t compile otherwise.
var hello = "Hello, variable!" // Go will infer that our variable is of type string
There is a way to shorten our declaration even more, by removing the keyword var. To do so, we also need to change the assignment operator from = to :=. Again, we can only use this method if we declare and assign a value to our variable in the same line.
hello := "Hello, variable!"
This method is much shorter than the previous ones, and is considered idiomatic. Therefore, you should use it whenever it is possible.
Similarly to variables, constants are made of four elements: a keyword, a name, a type and a value. As the name suggests, once we have assigned a value to a constant, no value can be reassigned to that constant. It makes constants very useful to hold stable values throughout the execution of your program, such as mathematical constants.
To define a constant, you will need to use the const keyword.
const pi float64 = 3.1416
As the value of a constant cannot change, reassigning this pi constant would produce a compiling error.
Similarly to variables, it exists a shorthanded version for declaring a constant. You can do so by removing the type from the declaration.
const pi = 3.1416
It is however impossible to remove the const keyword from the declaration. Go would indeed assume that we are trying to define a variable instead of a constant.
Similarly to other programming languages, it is possible in Go to define multiple variables (or constants) at the same time.
var ( first = "I" second = "love" third = "Go." )
It is important to notice several things here. Firstly, each variable (or constant) should be on its own line. Secondly, we voluntarily omitted the type (it would be totally valid to declare it). Lastly, as we use the keyword var (const for constants), we use the = assignment operator (and not the := operator).
In programming, a scope defines the boundaries within which we can access a variable (or constant).
Without scopes, one major issue could arise in our programs. This issue is known as naming conflict. Those conflicts arise when we are trying to declare a variable with a name that is already used somewhere else in our program by another variable. Unknowingly, we would then reassign the value of the first variable. This can lead to awkward and hard to track bugs.
To avoid those issues, Go is using what we call a lexical (or static) scope. In other words, the possibility to access a variable (or constant) depends on the location where this variable is declared in the first place. This lexical scope is the opposite of a dynamic scope where we can access variables declared in other functions, as long as those functions are located below in the stack.
In Go, this lexical scope is restricted by a block. This block itself is bounded by curly braces. In other words, a variable (or constant) can only be accessed within the block in which it is defined. For example, a variable defined inside of a function would only be accessible inside this function, and not outside of it.
This lexical rule also includes any child scope within the boundaries of the scope. For example, we could access the variables defined in a function from a conditional block, if this conditional block is located inside that function (the conditional block being the child scope).
It is also worth mentioning that a variable (or constant), declared in the global scope (outside of any function or condition blocks), will be accessible everywhere in our program. The global scope is indeed the parent scope of all the other scopes defined in our program. It is however advised to use this global scope with caution, as using it could lead to naming conflicts in our programs.
It is also important to note that any variable or constant declared in the global scope should be declared with a keyword (const or var). Failing to do so will lead to a compiler error.
In order to illustrate this concept of scope, let’s create the following two programs.
In this program, we define two functions. The first function, main, will access our variable x defined in the global scope as well as calling our second function. This second function, testScope, accesses the same global variable, and print it to the console too (with a "test" string concatenated).
In this program, we define the variable x inside the main function. We also call the testScope function from our main function. TestScope tries to print x to the console as well. However, writing the program in such a way will provoke a compiling error, as x is unaccessible from the testScope function. Indeed, x is defined inside the block of the main function, and can only be accessed inside that same block.
In this tutorial, we have continued our journey through the basic concepts of Go. We have explored the concepts of variables, constants and scopes. Mastering those concepts is fundamental in order to continue our journey, and explore the advanced parts of the Go language. In our next tutorial, we will explore control structures in Go.