Table of Contents
GoLang Data Types With Examples
Datatypes specify the type of data that a variable can hold. Variables are used to store data on memory in a programming language. Go is a statically typed language, which means on GoLang, a variable must have a type defined. And once a type is assigned to a variable it cannot be changed. Type of variables can be set implicitly or explicitly. In this Article, we have covered all the Data types in the GoLang with example
Data types in Go
There are some built-in variable types in Go. Variable types can be broadly categorized into two:
- Basic Types
- Composite Types
Basic Types
Boolean (bool)
- This bool type can be used to store true or false, and only true or false.
- By default, "false" will be assigned to the variable of this data type unless specified.
- Logical operators like AND, OR will produce Boolean types as output
Example code [bool]
- In this code, we will be seeing the default value of a boolean datatype and the output type of logical operations
package main
import "fmt"
func main() {
// Declaring variable without value; default value will be false
var ask bool
fmt.Printf("Default value of boolean datatype is %t\n",ask)
// And operation
Operation_and := 32 < 33 && 53 > 55
fmt.Printf("Data type of and Operation is %T and it values is %t\n",Operation_and,Operation_and)
// Or operation
Operation_or := 32 < 33 || 53 > 55
fmt.Printf("Data type of or Operation is %T and it values is %t\n",Operation_or,Operation_or)
}
Execution output:
[root@LDH datatypes]# go run . Default value of boolean datatype is false Data type of and Operation is bool and it values is false Data type of or Operation is bool and it values is true
Integers (int)
- This type can store whole numbers. There are different fixed int types:
- uint8, unit16, uint32, uint64
- int8, int16, int32, int64
- Alias types: byte (uint8), rune (int32), int, uint
1. The int, uint, and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems
2. uint can only store positive number , in a 32 bit system it can store values from 0 to 4294967295
3. int in a 32 bit system can store values from -2147483648 to-2147483648
Example code 1 [int]
Below example code shows the usage of int32 datatype and the bit size of default int
package main
import (
"fmt"
"math/bits"
)
func main() {
var basket int32 = -3
fmt.Printf("datatype of basket is %T and its values is %d\n",basket,basket)
//UintSize is to determine the bit size of the int,
sizeOfIntInBits := bits.UintSize
fmt.Printf("deafult int size is %d\n",sizeOfIntInBits,sizeOfIntInBits)
}
Execution output:
[root@LDH datatypes]# go run . datatype of basket is int32 and its values is -3 deafult int size is 64
Example code 2 [uint32]
Below example shows the usage of uint32, but with a negative value assigned to the variable. So we can expect an error as the uint data type doesn't support negative value
package main
import (
"fmt"
"math/bits"
)
func main() {
// Assigning negative value to a uint variable to see the execution error
var basket uint32 = -3
fmt.Printf("datatype of basket is %T and its values is %d\n",basket,basket)
sizeOfIntInBits := bits.UintSize
fmt.Printf("deafult int size is %d\n",sizeOfIntInBits,sizeOfIntInBits)
}
Execution output:
[root@LDH datatypes]# go run . # command-line-arguments ./integers_uint.go:7:24: cannot use -3 (untyped int constant) as uint32 value in variable declaration (overflows)
Floats (float)
Float data type variables can store floating point numbers like 12.34 or -12.34. There are float32 and float64 types available. When a variable is initializes with a decimal value via implicit initialization (:=) , default datatype will be float64
Example code [float]
package main
import "fmt"
func main(){
var answer float64
answer = 36.3/7
fmt.Printf("the answer is %f",answer)
}
Execution output:
[root@LDH datatypes]# go run . the answer is 5.185714
Complex Numbers (complex)
complex data type can store complex number which can real and imaginary part like 35+56i. There are complex64 and complex128 types available. When a variable is initializes with a decimal value via implicit initialization (:=) , default datatype will be complex128.
Example code [complex]
The below example code shows the initializes of complex data type in two ways
package main
import "fmt"
func main(){
//Initialize way 1
var complex_explicit complex64 = 6 +7i
//Initialize way 2
number :=complex(8,9)
fmt.Printf("Complex number is %e\n",complex_explicit)
fmt.Printf("Complex number is %e\n",number)
}
Execution output:
[root@LDH datatypes]# go run . Complex number is (6.000000e+00+7.000000e+00i) Complex number is (8.000000e+00+9.000000e+00i)
String
String type can store series of characters. The string can be initialized by two ways.
- Using double quotes ("): When used escape characters are respected
- Using back quotes (`) : When used escape characters are not respected
Example Code [String]
Below example shows both method of declaration of strings, which shows the escape characters
package main
import "fmt"
func main(){
// Using double quotes, for respecting escape characters
var sunday string = "Hello \n World"
// Using escape quotes which doesnt respecting escape characters
var saturday string = `Hello \n World`
fmt.Printf("%s\n",sunday)
fmt.Printf("%s\n",saturday)
}
Expected output:
[root@LDH datatypes]# go run . String is Hello World String is Hello \n World
Alias types
Byte: Byte is an alias for uint8. Byte is used to represent the ASCII character
var rbyte byte := 'a'
Rune: Rune is an alias for int32. Rune is used to represent all UNICODE characters
Rune is declared by using single quotes
hub := 'µ'
Composite Types
Arrays
Array is declared with a size. Array can be declared with and without values. The length of the array cannot be changed
- Array with size and values
Array1 := [len]Type{"val1","val2"}
- Array without values
Array2 := [len]Type{}
Var Array2[len]Type
Example Code [Arrays]
Below example code shows:
- array initialization with values
- array initialization without values
- using type int and string in arrays
- copying content from one array to another
package main
import "fmt"
func main() {
// Initializing array1 with type string and with values
array1 := [5]string{"l","i","n","u","x"}
fmt.Println(array1)
// Initializing array2 with type int and with values
array2 := [3]int{3,3,2}
fmt.Println(array2)
// Initializing array3 with type int and without values
array3 := [3]int{}
// Copying arraycontent from array2 to array3
array3 = array2
fmt.Println(array3)
}
Expected output:
[root@LDH datatypes]# go run . [l i n u x] [3 3 2] [3 3 2]
Slices
Slice is a dynamic light weight data structure. It is similar to array with index values, but the size is not fixed like an array. An array cannot grow or shrink in size but a slice can change its length.
Slice can initialized using make or by direct initialization. Slice uses array reference in the backend.
Slice can also be created from an array, slice of a slice is also possible
var s1 = []int{value1, value2, value3, value4, value5} var s2= []string var sliceB =make([]Int,length,Capacity)
Example code [Slices]
Below example code show:
- Declaration of Slices with initial value
- Declaration of Slices with make function
- Appending a new value to a Slice
- Creating a slice from an array
package main
import "fmt"
func main() {
// Slice is created with values
var Vegetables = []string{"eggplant", "cabbage", "tomato", "carrot", "potato", "curryleaf"}
fmt.Println(Vegetables)
// New values are appended to the existing slices
Vegetables = append(Vegetables, "pumpkin", "Raddish")
fmt.Println(Vegetables)
// Array with length 5 is created
var Numbers = [5]int{1, 2, 3, 4, 5}
fmt.Println(Numbers)
// Slice is created without initial values
Number_slice := make([]int, 4, 100)
// Slice is created from an Array.
Number_slice = append(Numbers[1:])
fmt.Println(Number_slice)
}
Expected output:
[root@LDH datatypes]# go run . [eggplant cabbage tomato carrot potato curryleaf] [eggplant cabbage tomato carrot potato curryleaf pumpkin Raddish] [1 2 3 4 5] [2 3 4 5]
Channels
Channels in Go are used to send and receive values to and from go routines. By default a channel is bidirectional. Send and receive is done by <- operation. There are two types of channels, buffered and unbuffered channels.
Unbuffered Channels
- Unbuffered channels doesn't have the capacity to hold any values.
- Thus if there is no go routine is send on a channel, the receive on that channel will be blocked
- If there is no go routine to receive on a channel, the send on the channel will be blocked
Unbuffered channel can be declared using:
channelName := make(channel_name Type)
Example code [Unbuffered channel]
Below example shows :
- A channel with no buffer length is initialized
- Two Go routines is writing to the same channel
- Only one input is received and printed
- We will see that since the second value in the channel is not having anybody to receive, the execution is blocked [the print in the function Temperature is not executed]
package main
import (
"fmt"
"time"
)
func main() {
// Unbuffered channel is declared
fifo := make(chan string)
// go routine 1
go Temperature(fifo)
// go routine 2
go Temperature(fifo)
// Fetching the value from go routine
value := <-fifo
// On receieving and print 1 value from 2 go routines
fmt.Println(value)
time.Sleep((1 * time.Second))
}
func Temperature(fifo chan string) {
// Providing an input to channel
fifo <- "High"
// Printing a string to see if the execution is completed or blocked
fmt.Println("go routine executed")
}
Expected output:
[root@LDH datatypes]# go run . go routine executed High
Buffered Channel:
- Buffered channels have the capacity to hold any values., Capacity is mentioned during the channel declaration
- the receive on that channel will be blocked, only if the channel is nil or empty
- the send on the channel will be blocked, only if the channel is nil or empty
Unbuffered channel can be declared using:
channelName := make(channel_name Type,capacity)
Example code [Buffered channel]:
Below example is similar to unbuffered channel with only difference of giving channel capacity :
- A channel with a buffer length of 2 is initialized
- Two Go routines is writing to the same channel
- Only one input is received and printed
- We will see that since the second value in the channel is not having anybody to receive, but the execution of the function temperature is not blocked.
package main
import (
"fmt"
"time"
)
func main() {
// Buffered channel is declared
fifo := make(chan string,2)
// go routine 1
go Temperature(fifo)
// go routine 2
go Temperature(fifo)
// Fetching the value from go routine
value := <-fifo
// On receieving and print 1 value from 2 go routines
fmt.Println(value)
time.Sleep((1 * time.Second))
}
func Temperature(fifo chan string) {
// Providing an input to channel
fifo <- "High"
// Printing a string to see if the execution is completed or blocked
fmt.Println("go routine executed")
}
Expected output:
[root@LDH datatypes]# go run .
go routine executed
High
go routine executed
Pointers
Pointer are used to store memory address of another variable. The zero value of a point is nil
Pointer can be declared as:
var pointer_name Type*
eg: var debt int*
& is used to assign an address of a variable to a pointer
pointer := &Variable
Example code [Pointers ]:
In the below example code, It can be seen
- A variable is initialized
- A pointer is initialized and the memory address of the variable is assigned
- Pointer address and the value on the memory location is also printed
package main
import "fmt"
func main() {
//Declaring a variable with type int
var apple int = 58
// Declaring a pointer with type int
var basket *int
// Assigning memory address of the variable to pointer using '&'
basket = &apple
// Printing address stored in memory
fmt.Println("memory address is ",basket)
// Printing values of the variable
fmt.Println("values in the memory address is ",*basket)
}
Expected output:
[root@LDH datatypes]# go run . memory address is 0xc0000a8000 values in the memory address is 58
Function
Functions are piece of code that can be reused inside a program. Function is declared as:
func name(parameter list with types) return type { <Body> }
Example code [Pointers ]
In the Below example, a simple use of function is seen:
- A function for adding a number is written and have assigned to a variable
- In arguments, parameter along with types is given
- Return type is also specified in the function
- The function is reused in the code
package main
import "fmt"
func main() {
//Declaring function to a variable
Add := func(x int, y int) int {
Sum := x + y
return Sum
}
Answer := Add(3, 5)
fmt.Println("Answer is ", Answer)
//Reusing the function
Answer = Add(9, 3)
fmt.Println("Answer is", Answer)
}
Expected output:
[root@LDH datatypes]# go run . Answer is 8 Answer is 12
Interface
Interface are the custom type that is used to specify a set of one or more method signatures. This is very helpful when you want different types to behave in the same manner.
type name_of_interface interface{
//Method signature 1
//Method signature 2
}
Example code [Interface ]
The below example shows :
- The declaration of interface
- Multiple types behaving in the same way
- Method declaration
- Utilization of Interface
package main
import "fmt"
// Interface is declared
type Net_Usage interface {
NetuseCalc()
}
//Type JayDeep is declared as struct
type JayDeep struct {
Jan int
Feb int
March int
}
//Type Adiyan is declared as struct
type Adiyan struct {
Aug float32
Sep float32
Oct float32
}
func main() {
JayDeep_Use := JayDeep{Jan: 150, Feb: 400, March: 750}
Adiyan_Use := Adiyan{Aug: 80.3, Sep: 200.4, Oct: 450.7}
// Even though the object type differs(Adiyan & JayDeep), the behaviour remains same
Usage(JayDeep_Use)
Usage(Adiyan_Use)
}
// Method for Jaydeep to find a print Total interent usage
func (s JayDeep) NetuseCalc() {
Total_use := s.Jan + s.Feb + s.March
fmt.Println("Total internet usage is", Total_use)
}
// Method for Adiyan to find a print Total interent usage
func (s Adiyan) NetuseCalc() {
var Total_use float32
Total_use = s.Aug + s.Sep + s.Oct
fmt.Println("Total internet usage is", Total_use)
}
//Both Adiyan and Jaydeep is calulating and printing the total usage of net
// Hence we can use the interface and the signature from that interface
func Usage(N_U Net_Usage) {
N_U.NetuseCalc()
}
Expected output:
[root@LDH datatypes]# go run . Total internet usage is 1300 Total internet usage is 731.4
Map
Map in Go Lang is unordered pairs of key-value. It is similar to dictionary in python.
Map can be initialized as below
var name map[key_type]value_type
var name map[Key_type]value_type{
key1:value1,
key2:value2,
}
Zero value of map with no key value:pairs is nil
Example code [Map]
Below example code shows:
- Declaring nil map
- Specifying map literal value in the map
- Adding a key value pair in map
package main
import "fmt"
func main() {
// Declaring a nil map
var Age map[string]int
// Using shorthand declaration and
// using map literals
Age_2 := map[int]string{
90: "nighty",
99: "nightynighty",
}
// Adding key value pair
Age_2[27] = "twentyseven"
// Checking if a map is nil
if Age == nil {
fmt.Println("Map Age is nil")
} else {
fmt.Println("False")
}
fmt.Println(Age_2[27])
}
Expected output:
[root@LDH datatypes]# go run . Map Age is nil twentyseven
Struct
Struct is a collection of data. The type of the data can be same or different. It is container of related data of multiple data types. Struct can be considered as Slices with different data types
type struct_name struct {
// Fields
variable_name Type
}
Example code [Struct]:
In the below example code, It can be seen
- Struct is defined outside the main function
- Struct initialized without named fields
- Struct initialized with named fields
- Struct initialized with partial fields
Expected output:
package main
import "fmt"
type zoo struct {
animal string
age int
weight float64
}
func main (){
// Initialize struct without named fields
Carnivore := zoo{"Tiger",15,76.9}
fmt.Println(Carnivore)
// Initialize struct with named fields
Herbivore := zoo{
animal: "Zebra",
age: 10,
weight: 78.8}
fmt.Println(Herbivore)
// Initialize struct with partial types, Here weight is not specified
Omnivore := zoo{ animal: "Bear", age: 13}
fmt.Println(Omnivore)
}
Expected output:
[root@LDH datatypes]# go run . {Tiger 15 76.9} {Zebra 10 78.8} {Bear 13 0}