GoLang Data Types With Examples

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:

  1. Basic Types
  2. 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

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}

 

Search on LinuxDataHub

Leave a Comment