[Talking-Golang (Go)] Variable Declaration and Initialization

Variable Declaration and Initialization

Variable is the name given to a memory location to store a value of a specific type. There are various syntaxes to declare variables in Go. Let’s look at them one by one.

Since Go is strongly typed, variables declared as belonging to one type cannot be assigned a value of another type.

Declaring variables

var name type is the syntax to declare a single variable.

1
2
var age int // variable declaration
fmt.Println("My age is", age)

Declaring a variables with a initial values

Variable can also be provided a initial value when it is declared. The following is the syntax to declare variables with a initial value.

1
2
3
var age int = 29 // variable declaration with initial value

fmt.Println("My age is", age)

Type inference

If a variable has an initial value, Go will automatically be able to infer the type of that variable using that initial value. Hence if a variable has an initial value, the type in the variable declaration can be removed.

If the variable is declared using the following syntax

1
var name = initialvalue  

Go will automatically infer the type of that variable from the initial value.

In the following example, we can see that the type int of the variable age has been removed in line no. 6. Since the variable has an initial value 29, Go can infer that it is of type int.

1
2
var age = 29 // type will be inferred
fmt.Println("My age is", age)

Multiple variable declaration

Multiple variable declaration with a same type

Multiple variables can be declared using a single statement.

var name1, name2 type = initialvalue1, initialvalue2 is the syntax for multiple variable declaration.

1
2
3
var width, height int = 100, 50 //declaring multiple variables

fmt.Println("width is", width, "height is", height)

Multiple variable declaration with different types

There might be cases where we would want to declare variables belonging to different types in a single statement. The syntax for doing that is

1
2
3
4
var (  
name1 = initialvalue1
name2 = initialvalue2
)

The following program uses the above syntax to declare variables of different types.

1
2
3
4
5
6
var (
name = "naveen"
age = 29
height int
)
fmt.Println("my name is", name, ", age is", age, "and height is", height)

Short hand declaration

name := initialvalue is the short hand syntax to declare a variable.

1
2
count := 10 // automatically infer that count is of type int since it has been initialized with the integer value 10.
fmt.Println("Count =",count) // 10

It is also possible to declare multiple variables in a single line using short hand syntax.

1
2
3
name, age := "naveen", 29 //short hand declaration

fmt.Println("my name is", name, "age is", age) // my name is naveen age is 29

Short hand declaration requires initial values for all variables on the left-hand side of the assignment.

1
2
3
// name, age := "naveen" //error

// fmt.Println("my name is", name, "age is", age)

Short hand syntax can only be used when at least one of the variables on the left side of := is newly declared.

1
2
3
4
5
6
7
a, b := 20, 30 // declare variables a and b
fmt.Println("a is", a, "b is", b)
b, c := 40, 50 // b is already declared but c is new
fmt.Println("b is", b, "c is", c)
// b, c := 80, 90 // error, b and c is already declared, no newly declared
b, c = 80, 90 // assign new values to already declared variables b and c
fmt.Println("changed b is", b, "c is", c)
1
2
3
4
5
6
7
8
9
10
11
a := "a"
b := "b"
{
a := "a-inner" // note that it is used :=
fmt.Println("a = ", a) // a = a-inner

b = "b-inner" // note that it is used =, not used :=
fmt.Println("b = ", b) // b = b-inner
}
fmt.Println("a = ", a) // a = a, a has not been modified
fmt.Println("b = ", b) // b = b-inner, b has been update.

Declares a pointer variable

Declares a pointer variable with new function

The new function to be mentioned here is a built-in function in Go.

Using the expression new(Type) will create an anonymous variable of the Type type, initialize it to the zero value of the Type type, and then return the variable address, and the returned pointer type is *Type.

1
2
3
4
ptr := new(int)
fmt.Println("ptr address: ", ptr) // ptr address: 0xc000010098
// * Followed by the pointer variable, which means that the value is taken from the memory address
fmt.Println("ptr value: ", *ptr) // ptr value: 0

Declares a reference variable with make function

make is also used for memory heap allocation, but different from new, it is only used for chan, map, and slice memory creation, plus initializes their underlying data structures, and the type it returns is the three types themselves, not their pointer types, because of these three types They are reference types, so there is no need to return their pointers.

1
func make(t Type, size ...IntegerType) Type

Things you can do with make that you can’t do any other way:

  • Create a channel

  • Create a map with space preallocated

  • Create a slice with space preallocated or with len != cap

1
2
3
s := make([]int, 10, 100)      // slice with len(s) == 10, cap(s) == 100
m := make(map[string]int, 100) // map with initial room for ~100 elements
c := make(chan int, 10) // channel with a buffer size of 10

Note that because these three types are reference types, they must be initialized, but they are not set to zero, which is different from new.

1
2
p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable

That being said:

  • make(T) behaves like composite-literal syntax
  • new(T) behaves like var (when the variable is not initialized)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fmt.Println("-- MAKE --")
a := make([]int, 0)
aPtr := &a
fmt.Println("pointer == nil :", *aPtr == nil) // pointer == nil : false
fmt.Printf("pointer value: %p\n\n", *aPtr) // pointer value: 0x118eff0 # address to underlying array

fmt.Println("-- COMPOSITE LITERAL --")
b := []int{}
bPtr := &b
fmt.Println("pointer == nil :", *bPtr == nil) // pointer == nil : false
fmt.Printf("pointer value: %p\n\n", *bPtr) // pointer value: 0x118eff0 # address to underlying array

fmt.Println("-- NEW --")
cPtr := new([]int)
fmt.Println("pointer == nil :", *cPtr == nil) // pointer == nil : true
fmt.Printf("pointer value: %p\n\n", *cPtr) // pointer value: 0x0

fmt.Println("-- VAR (not initialized) --")
var d []int
dPtr := &d
fmt.Println("pointer == nil :", *dPtr == nil) // pointer == nil : true
fmt.Printf("pointer value: %p\n", *dPtr) // pointer value: 0x0

Initialize a pointer variable with &

& equivalent to new function

1
2
3
4
5
var dummy int    // declare a variable
ptr = &dummy // get the reference or point
fmt.Println("ptr address: ", ptr) // ptr address: 0xc000010098
// * Followed by the pointer variable, which means that the value is taken from the memory address
fmt.Println("ptr value: ", *ptr) // ptr value: 0

Declare values with Function parameters and return values

with the same type.

1
2
3
4
5
func split(a, b int) (x, y int) {    // declare a, b with the same type, and x, y with the same type.
x = b
y = a
return // equivalent to returning x, y
}

with the different types.

1
2
3
4
5
func split(a int, b string) (x string, y int) {    // declare a, b with the same type, and x, y with the same type.
x = b
y = a
return // equivalent to returning x, y
}

Exchange variables

If you want to exchange the values of two variables, you can simply use a, b = b, a, and the types of the two variables must be the same.

1
2
3
4
5
a := 1
b := 2
a,b = b,a
fmt.Println(a) // 2
fmt.Println(b) // 1

Anonymous variables

The varriable can only be declared once, and if it is declared multiple times, the compiler will report an error.

But there are exceptions, and this is about a special variable(_): anonymous variables, also called placeholders, or blank identifiers, which are represented by underscores.

Anonymous variables have three advantages:

  • Does not allocate memory, does not occupy memory space

  • You don’t need to worry about naming useless variable names

  • There will be no problems with multiple declarations

  • Usually we use anonymous receiving values that must be received, but not used.

1
2
3
a, _ := GetData()
_, b := GetData()
fmt.Println(a, b)

References

[1] Declaring Variables in Go - golangbot.com - https://golangbot.com/variables/

[2] Variables in Golang (Examples) | Learn Go Programming - https://golangr.com/variables/

[3] go - Why would I make() or new()? - Stack Overflow - https://stackoverflow.com/questions/9320862/why-would-i-make-or-new

[4] Make slices, maps and channels · YourBasic Go - https://yourbasic.org/golang/make-slice-map-channel/