We have already covered different aspects of using variables in golang such as variable scope and how to access variables across packages which also briefly talks about golang global variables. But in this tutorial we will make our hands dirty by deep diving into this topic further with practical examples.
GO Variable definition
A variable is a container pointing to a memory location where data is stored. In Go , a variable is declared using the var keyword followed by the name of the variable, the type of the variable. The type of variable also determines the kind of operations that can be applied to the variable.
Syntax
var username string
Rules for naming variables in golang
Go variables have rules that determine how variables should be created in our programs. These rules are:
- A variable name consists of alphabets, digits and underscores.
- Variables named can not have special characters in them like $, @, #, !.
- Variable name can not start with a number
- Variable names can not be the same as Go keywords like for , int, interface, struct type etc.
Different types of variable scope
In Go, a variable scope is the region/area in our program where a defined variable is accessible. Therefore a variable definition can be done at the package level, function level and block level. Scoping of variable results to two main of variables in Go name:
- Global variable
- Local variable
1. Golang Global variables
Global variable definition (To be accessed within same package)
A global variable is a variable that has been defined outside a function. A global variable can be accessed and modified inside a function, a block of code like for loop block and anywhere else in the package. Global variables hold their values throughout the lifetime of the program.
Example
package main
import "fmt"
var username string
func main() {
username = "John Doe"
fmt.Println("Username is ", username)
}
Explanation
In the above example, we define a global variable username
of type string
and zero value of “”
. In the main function , we assign the username
variable a new value of “John Doe”
. The print statement prints the new value of the username variable.
Output
$ go run main.go
Username is John Doe
Global variable definition (To be accessed across different packages)
In golang we tend to create multiple package files and compile them to have a single binary. If you have a requirement to access variable across packages then follow these thumb of rule:
- Declare the variable in sub-package and not in the main package. A package can be shared only if it is declared in sub-packages and not the other way around in golang
- Make sure the first letter of the variable is in Capital Letter i.e. Uppercase such as Mypath, Testdir etc. All other words in the variable can be upper or lowercase but the first letter must be uppercase.
- To access the variable, use
package_name.variable_name
Here I have a sub-package where I have defined a variable Mypath
:
package util
var Mypath string
func init() {
Mypath = "/tmp"
}
Let me access this variable from main package:
package main
import (
"fmt"
"global-vars/util"
)
func main() {
// Access global variable across package
fmt.Println("The path is: " + util.Mypath)
}
Output:
$ go run main.go
The path is: /tmp
Editing Global variables
The value of a global variable can be changed by any code throughout the package. For example a block of code in a loop or a function can access the global variable and change it. Please note that , in case you have multiple blocks of code changing the value of a global at the same time using goroutines , this will result in undesirable results caused by race conditions. To learn more about race conditions, read the Go Mutex Tutorial .
Example
package main
import "fmt"
var counter int
func main() {
for i := 0; i < 1000; i++ {
counter += 1
}
fmt.Println("Counter value is ", counter)
}
Explanation
In the above example, we define a global variable counter
with 0 as its initial value. In the main function we loop from 0 to 1000 and after every iteration, we increase the counter value by one using counter += 1
. This changes the value of the global variable , and the new value is accessible all over the package.
Output
$ go run main.go
Counter value is 1000
Global variable as a pointer
In the previous example, we have defined global variables that are assigned values. In this section, we learn how to define the global variable with pointer initialization. The zero value of a pointer global variable is nil. To define a pointer, add asterisk(*)
before the type of the variable. Since a pointer is a memory address of where data is stored, to access the value of the pointer user the ampersand (&)
operator before the pointer variable to get access to the actual value. Learn more about pointers in the Go pointer tutorial.
Example
package main
import "fmt"
var username *string
func main() {
newName := "John doe"
new_name := fmt.Sprintf("%s", newName)
username = &new_name
fmt.Println(*username)
}
Explanation
In the preceding example, we define a pointer global variable of type string. The asterisk(*) before the type of the variable, indicates pointer variable definition. In the main function, we assign the username
global variable a pointer to the newName
variable using username = &new_name
. We then print the value of the username pointer variable by adding the asterisk operator before the username pointer variable.
Output
$ go run main.go
John doe
Global variable and local variable preference
A local variable is a variable defined inside a function or a block of code like a loop. Local variables have a function and a block scope. In some cases you might define a global and local variable with the same name. In this case, the local variable will be used instead of the global variable.
Example
package main
import "fmt"
var language string = "No language"
func main() {
language := "Go language"
fmt.Println(language)
}
Explanation
In the above example, we define two variables of type string. The global variable is assigned the value “No language”
and the local variable is “Go language”
. When you print the value of the language variable, the value of the local variable
is printed out instead. This means a local variable will always take precedence over the global variable.
Output
$ go run main.go
No language
Go language
2. Local variable
A local variable is a variable declared inside a function or a block of code such as a loop. The scope of a local variable is limited to the function body and the block body. If a local variable is declared twice with the same name within a scope, a compile time error will be returned.When a block or function is done executing , the lifetime of the local variable comes to an end.
Example
package main
import "fmt"
func getUsername(firstname, lastname string) string {
username := fmt.Sprintf("%s %s", firstname, lastname)
return username
}
func main() {
firstname, lastname := "John", "Doe"
username := getUsername(firstname, lastname)
fmt.Println(username)
}
Explanation
In the above example, we define a local variable username inside the getUsername
function. The main function can not access the username variable because its access is limited to the getUsername
function only.
Output
$ go run main.go
John Doe
Disadvantages of Go global variables
- Global variables are editable, and these can result in undesired results. For example it can be challenging when the global variable is changed by another block of code unintentionally.
- In cases where multiple goroutines are running and changing the value of the global variable, it will result in race conditions and to avoid this we need to add more code to prevent it , such as adding Mutex, Atomic from the sync package.
- Global variables are only cleaned up when explicitly told so or when the program comes to an end.
- Global variables have no access control and any code block can access and change it.
- Global variables result in tight coupling of code. This becomes a headache when you try to decouple global variables.
Summary
In this tutorial , we learn about Go global and local variables and their scope. We also discuss the disadvantages of using Go global variables one main disadvantage being lock of access control. There , when using variables, consider using them as constants.
References
https://golangr.com/scope/
https://golangdocs.com/golang-global-variables
Related Keywords: golang global variables across packages, golang global variable initialization, golang global variable across files, golang global variables best practices, glonang global variable as pointer, Modifying glonang global variable