+8

[ENG] Golang: Part 3 - Exploring Fundamental Concepts

Hello world, I've returned to continue the series on Golang, following the foundational knowledge from the previous articles. In this part, we will dive straight into the concepts of pointers, structs, arrays, slices and maps. What are they? Let's get started.

Pointer

Compared with the pointer in C programing language, the pointer in Go also holds the memory address of a value. That means a pointer reference a location in memory where a value is stored rather than the value itself. Pointer in Go are variables which store the memory address of another variable.

Declaring pointers

var p *int

The code above is used to declare a pointer that points to a value of int type. In this case, the pointer doesn't point to any specific value, it is initialized with the default value of pointer, which is nil. For more clearly, Let's follow to the example below to understand the difference between using pointer and not using pointer:

package main

import "fmt"

func main() {
    var x int = 42
    var p int
    p = x     // Assign x to p

    fmt.Println("Value of x:", x)
    //42
    fmt.Println("Value of p:", p)
    //42
    x = 41

    fmt.Println("Value of  p:", p) 
    //42

}

In the above code, we have a variable x with an initial value of 42 and a variable p. A copy of the value of x is assigned to p, not the address of x, so when x changes its value to 41, the value of p remains 42.

package main

import "fmt"

func main() {
    var x int = 42
    var p *int  // Declare a pointer to an int
    p = &x     // Assign the memory address of x to the pointer p

    fmt.Println("Value of x:", x)
    //42
    
    fmt.Println("Value of x through pointer p:", p) // Access the value through the pointer
    //42
	x = 41

	fmt.Println("Value of x through pointer p:", p) // Access the value through the pointer
    //41
}

In this code, we declare a pointer p and assign the memory address of the variable x to it using the & operator. When the value of xchanges to 41, accessing the value through the pointer *p reflects the new value of 41. Pointers allow us to access and modify the value of the original variable through its memory address.

Structs

In Golang, we dont have object-oriented but this language has struct - which help us to make Go can do like OOP does. A struct is a collection of fields used to define the attributes or properties of an object. In real-world applications, we can use a struct to declare a data structure that represents the characteristics or requirements of an object. For instance, we might have a "User" struct that includes fields such as name, username, and age. Struct fields are accessed using a dot . character. Following the example below to know more about struct.

package main
import "fmt"

type User struct {
    name string
    username string
    age int
}

func main() {
    hieu := User{"pviethieu", "pviethieu", 24}
    hieu.age  = 25
    fmt.Println(hieu.age)
}

We also can insert a Struct to another Struct, for example:

type School struct {
    name string
    code string
}

type User struct {
    name string
    username string
    age int
    School // embed School struct to User struct 
}

From now, if you still use statement above to assign value to struct

hieu := User{"pviethieu", "pviethieu", 24}

You will get error like this:

fmt.Println(hieu)

./helloworld.go:17:43: too few values in struct literal of type User****

To fix this error, in Golang we have the feature named : Struct Literals. Now we can assign value but don't need to care about it enough values or not:

hieu := User{name:"Hieu Pham", username:"pviethieu", age:24}
fmt.Println(hieu)

/// result: {Hieu Pham pviethieu 24 { }}

Array

Array is a collection of items of same data type stored at contiguous memory locations. In Golang, we cannot resize the length of an array.

var a [10]int // declare an array, it's length has 10 item of  type `int`

a[0] = 98 // assign value for the first item of array

var primes := [6]int{2, 3, 5, 7, 11, 12} // an array has 6 items and assign values for it on the same line

Note that, we can define a struct type and create an array has struct type.

users := [5]User{
    User{name: "Hieu Pham", username: "pviethieu", age: 24},
    User{name: "Brian Pham", username: "brian", age: 24},
}

Slices

You have just learned about arrays in the previous section. However, arrays do not allow for resizing the length. In Golang, we have slices to do that. A slice in Golang consists of three main components:

  • Pointer: Points to the first element in the slice.
  • Length: The length of the slice is the actual number of elements it contains.
  • Capacity: The capacity of the slice is the maximum number of elements it can hold without needing additional memory allocation.

You can create a slice from an array or another slice using the following syntax:

slice := make([]T, length, capacity)
  • T is the data type of the elements in the slice.
  • length is the initial length of the slice.
  • capacity is the initial capacity of the slice. Alternatively, you can create a slice from an existing array or slice using slicing syntax:
newSlice := existingSlice[start:end]
  • existingSlice is the original slice.
  • start is the index of the first element in the new slice.
  • end is the index of the element just beyond the last element in the new slice

To append new elements to a slice, Go provides a built-in append function. For a more comprehensive understanding, follow the example below to learn:

package main

import "fmt"

func main() {
    // Initialize a slice to store users
    users := make([]string, 0)

    // Add users to the slice
    users = append(users, "Pham Hieu")
    users = append(users, "Brian Pham")
    users = append(users, "Hieu さん")

    // Display the list of users
    fmt.Println("User List:")
    for i, user := range users {
        fmt.Printf("%d. %s\n", i+1, user)
    }

    // Remove a task
    userToRemove := "Brian Pham"
    for i, user := range users {
        if user == userToRemove {
            users = append(users[:i], users[i+1:]...)
            break
        }
    }

    // Display the updated list of users
    fmt.Println("\nUpdated User List:")
    for i, user := range users {
        fmt.Printf("%d. %s\n", i+1, user)
    }
}

Maps

A map maps keys to values. It is also a collection, just like an array and a slice, and you can loop through a map in a manner similar to arrays and slices. However, because it's an unordered collection, each iteration will return key/value pairs in a different order, even if you have stored key/value pairs in a specific sequence. The followings example will show how we can initialize and mutate a map.

  // Initialize an user map
    user := make(map[string]int)

    // Add value to user
    user["age"] = 25
    user["gender"] = "male"
    user["job"] = "developer"

    // Update the value of age
    user["age"] = 26

    // Remove a information of user
    delete(user, "job")

    // Display the updated user
    fmt.Println("User:")
    for info, value := range user {
        fmt.Printf("%s: %d\n", info, value)
    }
    
    clear(user) // remove all key/values pairs from a map
}

Summary

The article explores essential concepts in Go (Golang) programming, covering pointers, structs, arrays, slices, and maps. It provides insights into how pointers reference memory locations, and how structs define object attributes. Arrays, fixed-size collections, and slices, dynamic-sized, are discussed, along with their creation and manipulation. Maps, collections that map keys to values, are presented, emphasizing their unordered nature. This article offers a comprehensive introduction to fundamental Go concepts. Thank you for reading! We appreciate your time and hope you found the article informative. If you feel that helpful for yourself, please consider leaving a vote for my article.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí