Built in Collections in Go
-
Built in means those collections which are part of the go language
syntax.
1. Array [n]T
-
fixed-size collection of elements of the same type. Array cannot be
resized
When we assign an array to a new variable or pass it to a function, Go creates a complete copy of the entire array.
var a [10]int
b = a // seperate copy is created for b
2. Slices [] = C++20(std::span) = Rust(Slice (written as &[T]))
Slice is a reference pointing to underlying array, slice can view/modify
elements of an underlying array.
Slice has 3 components
1. Pointer(to underlying array)
2. Length(number of elements in slice). len(slice)
3. Capacity(maximum number of elements it can hold). cap(slice): length
of undelying array - 1
nil slice: slice which does not point to any array(at present),
but can in future.
Can Slice increase the size of underlying array? No
If underlying array has a length of 10, the maximum number of
elements slice can hold is 10
If we try to append an 11th element using append(), Go
automatically does the following behind the scenes:
Allocates a brand new, larger underlying array in memory (usually
double the size)
Copies all the old elements into the new array.
Appends the new element.
Returns a new slice pointing to this new array. The original
array of size 10 remains untouched.
Slice Functions
-
append()
- append() will append the value to slice
- append only modifies the original underlying array if the slice's len is less than its cap. If len == cap, a new array is allocated.
package main
import "fmt"
func fun(b *[]int) {
// Trying adding beyond capacity
*b = append(*b, 5) //2,3,4,5
}
func main() {
// Create Slice
a := [4]int{1, 2, 3, 4}
fmt.Println("Before a:", a) //1,2,3,4
// Copy Slice
b := a[1:4] //2,3,4
fun(&b)
fmt.Println("After a:", a) //1,2,3,4. a remains same
fmt.Println("b:", b) //2,3,4,5
}
// Solution: Take array of size [5]
- nil slice, Create slice using make(), 2D Slice
func main() {
names := [4]string{"John", "Paul", "George", "Ringo"}
// Slice
a := names[1:3] // [Paul George]
a[0] = "XXX" // a=[XXX, George], names=[John Paul XXX George]
fmt.Printf("%d %d\n", len(a), cap(a)) //len=2, cap=3(underlying array size - 1)
// nil Slice
var b[]string
len(b), cap(b) // 0, 0
b = names[1:3] // b=["XXX", "George"]
// create Slice using make()
// c := make([]T, len, cap) OR c := make([]T, len)
d := make([]string, 3) //len=3
c := make([]string, 0, 2) //len=0,cap=2. Allocates memory of size=2 & points c to it.
c = names[2:4] // c=["George", "Ringo"]
// append slice
append(c, "Ram")
/***************** 2D Slice ******************/
// Method-1
var test [][]int
for i := 0; i < rows; i++ {
test = append(test, make([]int, cols))
}
// Method-2
test := make([][]int, rows)
for i := range vector {
test[i] = make([]int, cols)
}
/*******************************************/
// Create hashmap using make()
m := make(map[int]int)
}
3. Channels
4. Maps
-
A map is a hash table.
Maps in C++
Syntax: make(map[KeyType]ValueType, initialCapacity)
m := make(map[string]int) //map[key]value
m["gold"] = 100
Standard Library Provided Collections
1. Queue(Implemented using slice)
package main
import "fmt"
type test struct { //Declare a struct having slice which will act as queue
q []int
}
func Constructor() test {
return test{}
}
func (this *test) Push(x int) {
this.q = append(this.q, x) //Push() append x to queue
}
func (this *MyStack) Pop() {
this.q = this.q[1:] //Pop() Remove 1st element
}
func (this *MyStack) Top() int {
return this.q[0] //Top()
}
func (this *MyStack) Empty() bool { //Size()
if len(this.q) == 0 {
return true
}
return false
}
2. Stack using slice
3. struct
struct as class
-
Class is defined as struct type. Example: Person is defined of type
struct.
The struct type can be considered similar to a class, as it allows you to define fields and associated methods.
package main
import "fmt"
type student struct { // Define a struct type
name string
age int
marks []int // slice = dynamic ints
misc []interface{} // misc is a slice that can hold values of any type
}
// Define a method associated with the Person struct
// To associate a method with a struct, define a method with a receiver type that matches the struct type.
func (p Person) SayHello() {
fmt.Printf("Hello, my name is %s and I am %d years old.\n", p.name, p.age)
}
func main() {
// Create a new instance of Person
person := Person{name: "John", age: 30}
// Call the SayHello method
person.SayHello()
}
struct tagging
-
Defines variable name, type and field name which will map in yaml/json
file
test.yaml
default_action: allow
rules:
- user: "anonymous"
domain: "*.internal.example.com"
action: block
type Config struct {
//Field Name DataType StructTag: metadata. Look into yaml file when you find
default_action put into DefaultAction
DefaultAction string `yaml:"default_action"`
Rules []Rule `yaml:"rules"`
}
var cfg Config
bytes := os.ReadFile("test.yaml") //Read test.yaml content as bytes
yaml.Unmarshal(bytes, &cfg) //Stored bytes into Config struct