3. Variables, Constants, and Types

Once the Go Playground loads up, clear whatever is written on the screen and type:

Program: vandt.go


 1 package main
 2 
 3 import "fmt"
 4 
 5 var x int
 6 
 7 func main() {
 8 	p := 5
 9 	var q int
10 	fmt.Println("p is: ", p)
11 	fmt.Println("q is: ", q)
12 	fmt.Println("x is: ", x)
13 }

When we run the program, the output is:

p is:  5
q is:  0
x is:  0

3.1 Variable

A variable is a storage location for holding a value. The set of permissible values is determined by the variable’s type.

The var statement declares a list of variables.

A var statement can be at package or function level as seen in the above program.

Go can infer the type of the declared type. For integer literals Go infers type int, for floating-point literals Go infers type float64, and for complex literals Go infers type complex128 (the numbers in their names refer to how many bits they occupy). The normal practice is to leave types unspecified unless we want to use a specific type that Go won’t infer.

In the above program we have p := 5 which means that if an initializer is present, the type can be omitted; the variable will take the type of the initializer. Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type. Outside a function the := construct is not available.

Here Go automatically allocates some memory for the variable p - the size of the memory allocated here is that required by a single integer. Since we have also said p := 5, the integer value 5 is assigned to that memory space after the space is allocated. For variable q, no assignment has been stated. However, Go assigns a “zero-value” by default to most data types. For numeric fields, the value is 0.

Also note that p := 5 is the same as var p int = 5. Observe that in Go we declare the type1 after the variable name as in var q int. int is either 32 or 64 bits.

Variable names

Variable names in Go should be short rather than long. This is especially true for local variables with limited scope. Prefer c to lineCount. Prefer i to sliceIndex.

The basic rule: the further from its declaration that a name is used, the more descriptive the name must be. For a method receiver, one or two letters is sufficient. Common variables such as loop indices and readers can be a single letter (i, r). More unusual things and global variables need more descriptive names.

Finally, the convention in Go is to use MixedCaps or mixedCaps rather than underscores to write multiword names.

Multiple var declarations may also be grouped; const and import also allow this. Note the use of parentheses:

1 var (
2         x int
3         b bool
4 )

Multiple variables of the same type can also be declared on a single line:

var x, y int

makes x and y both int variables.

You can also make use of parallel assignment:

a, b := 35, 9

Which makes a and b both integer variables and assigns 35 to a and 9 to b.

Declared, but otherwise, unused variables are a compiler error in Go. The following code:

1 package main
2 
3 func main() {
4         var p int
5 }

generates this error:

p declared and not used

Note: A list of common mistakes you can avoid is available2.

Go is statically typed. Every variable has a static type, that is, exactly one type known and fixed at compile time: int, float32, *MyType, []byte, and so on. If we declare:

1 type MyInt int
2 
3 var i int
4 var j MyInt

then i has type int and j has type MyInt. The variables i and j have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion.

3.2 Constants

Constants are declared like variables, but with the const keyword. Constants can be character, string, boolean, or numeric values. Constants cannot be declared using the := syntax. Numeric constants are high-precision values.

Again, the convention in Go for constants is to use MixedCaps or mixedCaps rather than underscores or all CAPS to write multiword constant names.

1 const secretKey = 23232390 // Good
2 const SecretKey = 23232390 // Good
3 const secret_key = 23232390 // Bad
4 const SECRETKEY =23232390 // Bad

3.2.1 Typed and Untyped constants

1 // Untyped Constants.
2 const ui = 12345    // kind: integer
3 const uf = 3.141592 // kind: floating-point
4 const hi = "Hello"  // kind: string
5 
6 // Typed Constants
7 const ti int = 12345        // kind: integer with int64 precision restrictions.
8 const tf float64 = 3.141592 // kind: floating-point with float64 precision restrictions.

In the code snippet above, hi is an untyped string constant. An untyped constant is just a value, one not yet given a defined type that would force it to obey the strict rules that prevent combining differently typed values.

Rob Pike’s article3 has a detailed coverage of untyped and typed constants.

3.3 Named types

Named types are another way to create user defined types. They provide some interesting feature/functionality that is not always available in other languages. The standard library in Go used named types very effectively.

Two examples:

Clear the Go Playground screen of whatever is written there and type:

Program: sample1.go


 1 // Sample program to show how to declare and use a named type.
 2 package main
 3 
 4 import "fmt"
 5 
 6 // Duration is a named type that represents a duration
 7 // of time in Nanosecond.
 8 type Duration int64
 9 
10 func main() {
11 	// Declare a variable of type Duration
12 	var duration Duration
13 	fmt.Println(duration)
14 
15 	// Declare a variable of type int64 and assign a value.
16 	nanosecond := int64(10)
17 
18 	// Attemped to assign a variable of type
19 	// int64 (base type of Duration) to
20 	// a variable of type Duration.
21 	duration = nanosecond
22 
23 	// error: cannot use nanosecond (type int64) as type
24 	// Duration in assignment
25 }

When we run the program, the output is:

main.go:21: cannot use nanosecond (type int64) as type Duration in assignment

Clear the Go Playground screen of whatever is written there and type:

Program: sample2.go


 1 // Sample program to show how to declare and use a named type.
 2 package main
 3 
 4 import "fmt"
 5 
 6 // Duration is a named type that represents a duration
 7 // of time in Nanosecond.
 8 type Duration int64
 9 
10 func main() {
11 	// Declare a variable of type Duration
12 	var duration Duration
13 	fmt.Println(duration)
14 
15 	// Declare a variable of type int64 and assign a value.
16 	nanosecond := int64(10)
17 
18 	// Attemped to assign a variable of type
19 	// int64 (base type of Duration) to
20 	// a variable of type Duration.
21 	// duration = nanosecond
22 
23 	// error: cannot use nanosecond (type int64) as type
24 	// Duration in assignment
25 
26 	// Convert a value of type int64 to type Duration.
27 	duration = Duration(nanosecond)
28 	fmt.Println(duration)
29 }

When we run the program, the output is:

0
10

3.4 Boolean types

A boolean type represents the set of boolean truth values denoted by the predeclared constants true and false. The boolean type is bool.

3.5 Operators

Go supports the normal set of numerical operators. The table below lists the current ones and their relative precedence. They all associate from left to right.

Precedence Operator(s)
Highest * / % << >> & &^
  + - | ^
  == != < <= > >=
  <-
  &&
Lowest ||

Although Go does not support operator overloading (or method overloading for that matter), some of the built-in operators are overloaded. For instance, + can be used for integers, floats, complex numbers and strings (adding strings is concatenating them).

3.5.1 Boolean Operators

Syntax Description/Result
!b Logical not operator; false if Boolean expression b is true
a || b Short-circuit logical OR operator; true if either Boolean
  expression a or b is true
a && b Short-circuit logical AND operator; true if both Boolean
  expressions a and b are true
x < y true if expression x is less than expression y
x <= y true if expression x is less than or equal to expression y
x == y true if expression x is equal to expression y
x != y true if expression x is not equal toexpression y
x >= y true if expression x is greater than or equal to expression y
x > y true if expression x is greater than expression y

3.5.2 Arithmetic Operators

Syntax Description/Result
+x x
-x The negation of x
x++ Increments x by the untyped constant 1
x-- Decrements x by the untyped constant 1
x += y Increments x by y
x -= y Decrements x by y
x *= y Sets x to x multiplied by y
x /= y Sets x to x divieded by y; if the numbers are integers any
  remainder is discarded; division by zero causes a runtime panic
x + y The sum of x and y
x - y The result of subtracting y and x
x * y The result of multiplying y and x
x / y The result of dividing y and x; if the numbers are integers any
  remainder is discarded; division by zero causes a runtime panic

Although Go has sensible rules of precedence, it is recommended to use parentheses to make intentions clear. Using parentheses is particularly recommended for programmers who use multiple languages so as to avoid subtle mistakes.

Remember:

Short variable declarations can be used only inside functions

package main

myvar := 1 //error

func main() {  
}

Redeclaring variables using short variable declarations

You can’t redeclare a variable in a standalone statement, but it is allowed in multi-variable declarations where at least one new variable is also declared.

package main

import "fmt"

func main() {  
        i := 0
        i, j := 1, 2

        i, j = j, i
       fmt.Println(i, j)
}

The output is:

2 1

Remember contd.:

Accidental variable shadowing

The short variable declaration syntax is so convenient (especially for those coming from a dynamic language) that it’s easy to treat it like a regular assignment operation. If you make this mistake in a new code block there will be no compiler error, but your app will not do what you expect.

package main

import "fmt"

func main() {  
        x := 1
        fmt.Println(x)     //prints 1
        {
                fmt.Println(x) //prints 1
                x := 2
                fmt.Println(x) //prints 2
        }
        fmt.Println(x)     //prints 1 (bad if you need 2)
}

Exercise 2

Declare three variables that are initialized to their default values. Declare a variable of type string, int and bool. Display the values of those variables.

Exercise 3

Declare three variable that are initailized with a literal value. Declare a variable of type string, int and bool. Display the values of those variables.

Exercise 4

Declare an untyped and typed constant and display their values.

Exercise 5

Fahrenheit into Celsius

Write a Go program that converts a fixed temperature value in Fahrenheit into Celsius. Use the formula c = (f-32.0)*5.0/9.0 where c represents Celsius and f represents Fahrenheit.

3.6 Solutions

Exercise 2 Solution4.

Exercise 3 Solution5.

Exercise 4 Solution6.

Exercise 5 Solution7.

  1. http://golang.org/ref/spec#Types
  2. https://github.com/golang/go/wiki/CodeReviewComments
  3. https://blog.golang.org/constants
  4. http://play.golang.org/p/LtFP2Gkpdi
  5. http://play.golang.org/p/-3EAKb4ZGe
  6. http://play.golang.org/p/NZ1N721NbY
  7. http://play.golang.org/p/pol2hdWsTy