Now that you’ve had a glimpse of Go and completed your first exercise, we’re going to dive deep. Our first stop on our journeyis variables.
A variable holds data foryou temporarily so that you can work with it. When you declare a variable, it needs four things: a statement that you are declaring a variable, a name for the variable, the type of data it can hold, and an initial value for it. Fortunately, some of the parts are optional, but that also means there’s more than one way of defininga variable.
Let’s cover all the ways you can declarea variable.
Declaring a variable using var
Usingvar
is the foundational way todeclare a variable. Every other way we’ll cover is a variation of this approach, typically by omitting parts of this definition. A fullvar
definition with everything in place lookslike this:
var foo string = "bar"
The key parts arevar
,foo
,string
, and= "
bar"
:
var
is our declaration that we are defininga variablefoo
is the name ofthe variablestring
is the type ofthe variable= "bar"
is itsinitial value
Exercise 1.02 – declaring a variable using var
In this exercise, we’ll declare twovariables using the fullvar
notation. Then, we’ll printthem to the console. You’ll see that you can use thevar
notation anywhere in your code, which isn’t true for all variable declaration notations. Let’sget started:
- Create a new folder and add a
main.go
fileto it. - In
main.go
, add the main package name to the top ofthe file:package main
- Addthe imports:
import ( "fmt")
- Declare a variable at the package-level scope. We’ll cover what scopes are indetail later:
var foo string = "bar"
- Create the
main()
function:func main() {
- Declare another variable using
var
inour function: var baz string = "qux"
- Print both variables tothe console:
fmt.Println(foo, baz)
- Close the
main()
function:}
- Save the file. Then, in the new folder, runthe following:
go run .
The following isthe output:
bar qux
In this example,foo
is declared at the package level whilebaz
is declared at the function level. Where a variable is declared is important because where you declare a variable also limits what notation you can use todeclare it.
Next, we’ll look at another way to use thevar
notation.
Declaring multiple variables at once with var
We can use a singlevar
declaration to define more than one variable using avar
block or statement. Using this method is commonwhen declaring package-level variables. The variables don’t need to be of the same type, and they can all have their own initial values. The notation lookslike this:
var ( <name1> <type1> = <value1> <name2> <type2> = <value2>… <nameN> <typeN> = <valueN>)
You can have multiple of these types of declarations. This is a nice way to group related variables, thereby making your code more readable. You can use this notation in functions, but it’s rare to see itused there.
Exercise 1.03 – declaring multiple variables at once with var
In this exercise, we’ll declare multiplevariables using onevar
statement, each with a different type and initial value. Then, we’ll print the value of each variable to the console. Let’sget started:
- Create a new folder and add a
main.go
fileto it. - In
main.go
, add themain
package name to the top ofthe file:package main
- Addthe imports:
import ( "fmt" "time")
- Start the
var
declaration:var (
- Definethree variables:
Debug bool = false LogLevel string = "info" startUpTime time.Time = time.Now()
- Close the
var
declaration:)
- In the
main()
function, printeach variable tothe console:func main() { fmt.Println(Debug, LogLevel, startUpTime)}
- Save the file. Then, in the new folder, runthefollowing:
go run.
The following isthe output:
Figure 1.5: Output displaying three variable values
In this exercise, we declared three variables using a singlevar
statement. Your output will look different for thetime.Time
variable, but that’s correct. The format is the same, but the time itselfis different.
Using thevar
notation like this is a good way to keep your code well organized and save yousome typing.
Next, we’ll start removing someof the optional parts of thevar
notation.
Skipping the type or value when declaring variables
In real-world code, it’s not common to use the fullvar
notation. There are a few cases where you need to define a package-level variable with an initial value and tightly control its type. In those cases, youneed the full notation. It’ll be obvious when this is needed as you’ll have a type mismatch of some kind, so don’t worry too much about this for now. The rest of the time, you’ll remove an optional part or use the shortvariable declaration.
You don’t need to include both the type and the initial value when declaring a variable. You can use just one or the other; Go works out the rest. If you have a type in the declaration but no initial value, Go uses the zero value for the type you picked. We’ll talk about what a zero value is later in this book. On the other hand, if you have an initial value and no type, Go has a ruleset for how to infer the types that are needed from the literal valueyou use.
Exercise 1.04 – skipping the type or value when declaring variables
In this exercise, we’ll update our previous exercise so that it skips the optional initial values or type declarations from our variable declaration. Then, we’ll print the values to the console, as we did previously, to show that the result is the same. Let’sget started:
- Create a new folder and add a
main.go
fileto it. - In
main.go
, add themain
package name to the top ofthe file:package main
- Import the packageswe’ll need:
import ( "fmt" "time")
- Start themulti-variable declaration:
var (
- The
bool
value in the first exercise has an initial value of false. That’s abool
value’s zero value, so we’ll drop the initial value from its declaration as it is setby default: Debug bool
- The next two variables both have a non-zero value for their type, so we’ll drop theirtype declaration:
LogLevel = "info" startUpTime = time.Now()
- Close the
var
declaration:)
- In the
main()
function, print outeach variable:func main() { fmt.Println(Debug, LogLevel, startUpTime)}
- Save the file. Then, in the new folder, runthe following:
go run .
The following isthe output:
Figure 1.6: Output displaying variable values despite not mentioning the type while declaring the variables
In this exercise, we were able to update the previous code so that it uses a much more compact variable declaration. Declaring variables is something you’ll have to do a lot, and not having to use the notation makes for a better experience whenwriting code.
Next, we’ll look at a situation where you can’t skip any ofthe parts.
Type inference gone wrong
There are times when you’ll need to use all the parts of the declaration – for example, when Go isn’t able to guess the correct type you need. Let’stake a look at an exampleof this:
package mainimport "math/rand"func main() { var seed = 1234456789 rand.NewSource(seed)}
The following isthe output:
Figure 1.7: Output showing an error
The issue here is thatrand.NewSource
requires a variable of theint64
type. Go’s type inference rules interoperate a whole number, such as the one we used as anint
value. We’ll look at the difference between them in more detail later in this book. To resolve this, we will addint64
type to the declaration. Here’s howthat looks:
package mainimport "math/rand"func main() { var seed int64 = 1234456789 rand.NewSource(seed)}
Next, we’ll look at aneven quicker way todeclare variables.
Short variable declaration
When declaring variables in functions and functions only, we can use the:=
shorthand. This shorthand allows us to make our declarations even shorter. It does this by allowing us to not have to use thevar
keyword and by always inferring thetype from a requiredinitial value.
Exercise 1.05 – implementing a short variable declaration
In this exercise, we’ll update ourprevious exercise so that it uses a short variable declaration. Since you can only use a short variable declaration in a function, we’ll move our variable out of the package scope. Where beforeDebug
had a type but no initial value, we’ll switch it back so that it has an initial value since that’s required when using a short variable declaration. Finally, we’ll print it to the console. Let’sget started:
- Create a new folder and add a
main.go
fileto it. - In
main.go
, add themain
package name to the top ofthe file:package main
- Import the packageswe’ll need:
import ( "fmt" "time")
- Create the
main()
function:func main() {
- Declare each variable using the short variabledeclaration notation:
Debug := false LogLevel := "info" startUpTime := time.Now()
- Print the variables tothe console:
fmt.Println(Debug, LogLevel, startUpTime)}
- Save the file. Then, inthe new folder, runthe following:
go run .
The following isthe output:
Figure 1.8: Output displaying the variable values that were printed after using short variable declaration notation
In this exercise, we updated our previous code to use a very compact way to declare variables when we have an initial valueto use.
The:=
shorthand is very popular with Go developers and the most common way in which variables get defined in real-world Go code. Developers like how it makes their code concise and compact while still being clear as towhat’s happening.
Another shortcut is declaring multiple variables on thesame line.
Declaring multiple variables with a short variable declaration
It’s possible to declare multiple variables atthe same time using a short variable declaration. They must all be on the same line, and each variable must have a corresponding initial value. The notation looks like<var1>, <var2>, …, <varN> := <val1>, <val2>, …, <valN>
. The variable names are on the left-hand side of:=
, separated by,
. The initial values are on the right-hand side of:=
again, each separated by,
. The leftmost variable name gets the leftmost value. There must be an equal number of namesand values.
Here is an example that uses our previousexercise’s code:
package mainimport ( "fmt" "time")func main() { Debug, LogLevel, startUpTime := false, "info", time.Now() fmt.Println(Debug, LogLevel, startUpTime)}
The following isthe output:
Figure 1.9: Example output displaying the variable values for the program with a variable declaring function
Sometimes, you do see real-world code like this. It’s a little hard to read, so it’s not common to see it in terms of literal values. This doesn’t mean this isn’t common, though – it’s very common when calling functions that return multiple values. We’ll cover this in detail when welook at functions later inthis book.
Exercise 1.06 – declaring multiple variables from a function
In this exercise, we’ll call a function that returns multiple values, and we’ll assign each value to a new variable. Then, we’ll print the values to the console. Let’sget started:
- Create a new folder and add a
main.go
fileto it. - In
main.go
, add themain
package name to the top ofthe file:package main
- Import the packageswe’ll need:
import ( "fmt" "time")
- Create a function that returnsthree values:
func getConfig() (bool, string, time.Time) {
- In the function, return three literal values, each separatedby
,
: return false, "info", time.Now()
- Closethe function:
}
- Create the
main()
function:func main() {
- Using a short variable declaration, capture the values that were returned from the function’s threenew variables:
Debug, LogLevel, startUpTime := getConfig()
- Print the three variables tothe console:
fmt.Println(Debug, LogLevel, startUpTime)
- Close the
main()
function:}
- Save the file. Then, in the new folder, runthe following:
go run .
The following isthe output:
Figure 1.10: Output displaying the variable values for the program with the variable declaring function
In this exercise, we were able to call a function that returned multiple values and capture them using a short variable declaration in one line. If we used thevar
notation, it would looklike this:
var ( Debug bool LogLevel string startUpTime time.Time)Debug, LogLevel, startUpTime = getConfig()
Short variable notation is a big part of how Go has the feel of adynamic language.
We’re not quite done withvar
yet, though – it still has a useful trick upits sleeve.
Using var to declare multiple variables in one line
While it’s more common to use a short variable declaration, you can usevar
to define multiple variables on a single line. One limitation of this is that, when declaring the type, all the values must have the same type. If you use an initial value, then each value infers its type from the literal value so that they can differ. Here’san example:
package mainimport ( "fmt" "time")func getConfig() (bool, string, time.Time) { return false, "info", time.Now()}func main() { // Type only var start, middle, end float32 fmt.Println(start, middle, end) // Initial value mixed type var name, left, right, top, bottom = "one", 1, 1.5, 2, 2.5 fmt.Println(name, left, right, top, bottom) // works with functions also var Debug, LogLevel, startUpTime = getConfig() fmt.Println(Debug, LogLevel, startUpTime)}
The following istheoutput:
Figure 1.11: Output displaying variable values
Most of these are more compact when using a short variable declaration. This fact means they don’t come up in real-world code much. The exception is the same type-only example. This notation can be useful when you need many variables of the same type, and you need to control thattype carefully.
Non-English variable names
Go is a UTF-8 compliant language, which means you can define variables’ names using alphabets other than the Latin alphabet that, for example, English uses. There are some limitations regarding what the name of a variable can be. The first character of the name must be a letter or_
. The rest can be a mixture of letters, numbers, and_
. Let’s have a look at what thislooks like:
package mainimport ( "fmt" "time")func main() { デバッグ := false 日志级别 := "info" ይጀምሩ := time.Now() _A1_Μείγμα := "" " fmt.Println(デバッグ, 日志级别, ይጀምሩ, _A1_Μείγμα)}
The following isthe output:
Figure 1.12: Output showing variable values
Note
Languages and language: Not all programming languages allow you to use UTF-8 characters as variables and functionnames. This feature could be one of the reasons why Go has become so popular in Asian countries, particularlyin China.