Data Types and Variables in Go

In this article, we are going to look at some of the basic data types in Go and how we can declare variables and constants. Despite being a statically typed language, Go provides easy syntax to declare variables without explicitly defining data types.

Data Types and Variables in Go

Variables & Data Types

What is a variable?

A variable is a named storage location for a value. In Go, every variable has a type. For example, string stores text, while int stores whole numbers.

Data types

Go gives us several built-in data types.

TypeUseZero value
boolStores true or false.false
stringStores UTF-8 text.""
intStores a signed integer. Its size is either 32 or 64 bits depending on the platform.0
uintStores an unsigned integer. Its size is either 32 or 64 bits depending on the platform.0
int8Stores an 8-bit signed integer from -128 to 127.0
uint8Stores an 8-bit unsigned integer from 0 to 255.0
int16Stores a 16-bit signed integer from -32768 to 32767.0
uint16Stores a 16-bit unsigned integer from 0 to 65535.0
int32Stores a 32-bit signed integer.0
uint32Stores a 32-bit unsigned integer.0
int64Stores a 64-bit signed integer.0
uint64Stores a 64-bit unsigned integer.0
uintptrStores an integer large enough to hold the bit pattern of a pointer.0
float32Stores a 32-bit floating-point number.0
float64Stores a 64-bit floating-point number.0
complex64Stores a complex number with float32 real and imaginary parts.(0+0i)
complex128Stores a complex number with float64 real and imaginary parts.(0+0i)
byteAlias for uint8.0
runeAlias for int32; commonly used for Unicode code points.0
errorRepresents an error value.nil

Zero value

Unlike languages where an uninitialized variable may hold null or undefined, Go gives every variable a zero value. A bool becomes false, an int becomes 0, and a string becomes an empty string.

Declaring a variable

To declare a single variable, you can use the following syntax.

var variableName dataType = initialValue

initialValue is optional. If you do not give an initial value in the variable assignment, it will hold the zero-value of its data type.

var integer1 int = 15
var integer2 int8 = -25
var integer3 int32 // default 0
var float1 float32 = 63.2
var string1 string = "Hello World!"
var boolean1 bool // default false
var boolean2 bool = true

You can later assign a new value to an existing variable using normal assignment.

// variableName = newvalue
integer1 = -15
integer2 = 25
integer3 = 965
float1 = -52.99
string1 = "Hello There :)"
boolean1 = true
boolean2 = false

Variable name convention

Go recommends writing variable names in simple word or camelCase. Even under_score variable names are valid, they are not idiomatic.

Type Inference

Even though Go is statically typed, we do not always have to write the type manually. If the initial value is clear, Go can infer the type.

var variableName = initialValue

Go infers the type from initialValue. This syntax only works when the variable has an initial value.

var integer1 = 52 // int
var string1 = "Hello World" // string
var boolean1 = false // bool

Short-hand notation

Go also provides a shorthand syntax. With this form, we can drop both var and the explicit type.

variableName := initialValue

When Go sees :=, it knows we are declaring a new variable with an initial value. We cannot use this syntax to assign a value to an already declared variable unless at least one variable on the left side is new.

integer1 := 52 //int
string1 := "Hello World" //string
boolean1 := false //bool

Multiple variable declarations

You can declare multiple variables of the same data type in a single statement using the syntax below.

var var1, var2, var3 int

You can also assign initial values to these variables. You must assign all the variables with an initial value.

var var1, var2, var3 int  = 1, 2, 3

You can also drop the data type declaration in this syntax and let Go infer the types from the initial values. This lets us declare variables of different types on a single line.

var var1, var2, var3 = 1, 2.2, false

You can also use the shorthand notation instead of the above statement.

var1, var2, var3 := 1, 2.2, false

You can also use multiple lines to declare variables of different data types with a single use of var keyword. In this syntax, you do not have to provide initial values to all the variables.

var (
    var1        = 50
    var2        = 25.22
    var3 string = "Telefonía"
    var4 bool
)

More on short-hand notation

The shorthand notation syntax := can only be used inside a function body. Also, it can only be used when at least one of the variables on the left side of := is newly declared.

Shorthand syntax will come in handy when the value of a variable is assigned at runtime and the data type of the value is not known beforehand. For example, a value received from a function call (example below).

package main

import (
	"fmt"
	"math"
)

func main() {
	a, b := 145.8, 543.8
	c := math.Min(a, b)
	fmt.Println("The minimum value is ", c)
}

// The minimum value is  145.8

Type conversion

In Go, you cannot perform add or subtract (or any arithmetic) operations on variables to two different data types. So variables first must be converted to the same data type.

In Go, this conversion is very simple. Just wrap any variable inside parenthesis with the data type prefix that you want to convert that variable into. The syntax to convert data to a data type is type(*var*).

var1 := 10 // int
var2 := 10.5 // float64// *illegal*
// var3 := var1 + var2// *legal*
var3 := var1 + int(var2) *// var3 => 20*

If you have a string (which is a slice of byte or uint8 values), you can convert it to a different integer data type using []type() syntax.

var1 := "Hello"
var2 := []int32(va1)

Defining a type

Go provides some built-in types but we can create our own types derived from these built-in types as well as aliases to existing types.

Derived Type

You create a new derived type from any built-in or user-defined type using type keyword.

type newType fromType

In the this syntax, newType is a new type derived from the fromType. The newType has all the properties of the fromType, however, now we can add additional properties on it without modifying fromType.

You can assign any fromType value to a newType variable or constant, however, fromType and newType types are not comparable since they are two different types. But we can use type conversion to convert the value fromType to newType and vice-versa.

For example, if you want to define your own data type float which should have all the properties of float64 type, then you can define it like below.

type float float64

In the program below, Go will create float type which will be derived from the float64 built-in type. You can use this type as a normal Go data type and declare variables of the float data type.

Go does not have a built-in float type name. If we want that name in our own code, we can define it as a custom type derived from float64.

package main

import "fmt"

type float float64

func main() {
	var f float = 52.2
	fmt.Printf("f has value %v and type %T\n", f, f)
}

// f has value 52.2 and type main.float

In this program, we define float as a type derived from float64, then create a variable f of that new type.

f has value 52.2 and type main.float

This program prints main.float because float is a custom type and it must belong to a package. Type can be defined anywhere in the program, like in a function or a condition block.

If you define a new type with beginning with a lowercase letter, then it won’t be exported from the package and other packages won’t be able to use it. We will discuss this in packages and modules tutorials.

package main

import "fmt"

type float float64

func main() {
    var f float = 52.2
    var g float64 = 52.2
    fmt.Println("f == g", f == g)
}

Also, float is not automatically compatible with float64. They share the same underlying representation, but they are still different types.

package main

import "fmt"

type float float64

func main() {
	var f float = 52.2
	var g float64 = 52.2
	fmt.Println("f == g", f == g)
}

// ./prog.go:10:29: invalid operation: f == g (mismatched types float and float64)

So this program does not compile. The compiler reports this error.

invalid operation: f == g (mismatched types float and float64)

However, you are free to compare a variable of any type with a compatible value directly. For example, f == 52.2 returns true because 52.2 is a valid float type as well.

Type Alias

A type alias is an alternative name for an existing type. We define a type alias using the following syntax.

type aliasName = oldType

In this syntax, aliasName is another name for the already defined type oldType. Unlike a derived type, an alias does not create a new type.

package main

import "fmt"

type float = float64

func main() {
	var f float = 52.2
	var g float64 = 52.2
	fmt.Println("f == g", f == g)
}

// f == g true

In this program, float is just another name for the built-in float64 type. Since these are the same type, their values are comparable.

Unless very necessary, you should not create a type alias since it doesn’t do anything important. However, type alias can be useful when you have to refactor a large amount of code (ref).

What is a constant

A constant is a named value that cannot be changed. Constants are declared with the const keyword and must have an initial value.

const const_name [data_type] = fixed_value

data_type is optional because Go can infer it from fixed_value.

In Go, constant value must be known during compile time. If you are trying to assign value returned by a function call, that won’t work. const a = math.Sqrt(4) is an illegal statement as value of a is computed during run time.

Multiple constants declaration

Like variables, multiple constants can be declared in one statement.

const const_1, const_2 = value_1, value_2

Or you can use the multiple-line variable declaration syntax.

const (
    const_1 = value_1
    const_2 = value_2
)

In a parenthesized const declaration, Go can implicitly repeat the previous expression.

const (
	a = 1 // a == 1
	b = 2 // b == 2
	c     // c == 2
	d     // d == 2
)

The iota expression

Go provides a keyword iota that can be used when declaring enumerated constants. This keyword yields an incremented value by 1 starting from 0, each time it is used.

const (
    a = iota // a == 0
    b = iota // b == 1
    c = iota // c == 2
    d        // d == 3 (implicitely d = iota)
)

Use _ (blank identifier) to skip a value. _ will receive the value of iota + 1 but will save the value in the garbage scope.

const (
	a = iota + 1 // a == 1
	_            // (implicitly _ = iota + 1 )
	b            // b == 3 (implicitly b = iota + 1 )
	c            // c == 4 (implicitly c = iota + 1 )
)
package main

import "fmt"

func main() {
	const (
		a = iota + 1 // a == 1
		_            // (implicitly _ = iota + 1 )
		b            // b == 3 (implicitly b = iota + 1 )
		c            // c == 4 (implicitly c = iota + 1 )
	)

	fmt.Println(a, b, c)
}

// 1 3 4

One crucial to remember here is that, iota can only be used with variables defined with const. iota will always return an integer of type int. The scope of iota is restricted to the const block.One crucial to remember here is that, iota can only be used with variables defined with const. iota will always return an integer of type int. The scope of iota is restricted to the const block.

const a = iota // 0
const b = iota // 0

const (
  c = iota // 0
  d = iota // 1
)

const (
  e = iota // 0
  f = iota // 1
)

As you can see from this example, iota value resets to 0 whenever const keyword appears in the program.

Numeric Expressions

Numeric constants (like 1, 2, 3, etc.) are free to be mixed and matched in expressions and a type is needed only when they are assigned to variables or used in a place where a data type has to be explicitly declared.

But the result of any mathematical expression depends on the data type of the operands. For example, the division of two integers will be an integer.

var a = 11/2 // a == 5

This happens as both operands hold data type of int. If you change any of the operand’s data type to float32, the result will be a float32 value.

var a = 11.0/2 // 5.5 (float64)
var b = float32(11)/2 // 5.5 (float32)
#golang #basics