Ghi chú học Go (5)

Mục lục

I. Cấu trúc dữ liệu (Struct)

  1. Khai báo cấu trúc

  2. Truy cập thành phần của cấu trúc

  3. Truyền cấu trúc vào hàm

  4. Con trỏ đến cấu trúc

II. Slice trong Go

  1. Khởi tạo slice

  2. Hàm len() và cap()

  3. Slice rỗng (nil)

  4. Cắt slice

  5. Hàm append() và copy()

I. Cấu trúc dữ liệu (Struct)

1. Khai báo cấu trúc

Trong Go, mảng chỉ có thể chứa các phần tử cùng kiểu dữ liệu, nhưng với cấu trúc bạn có thể định nghĩa các kiểu dữ liệu khác nhau cho từng thành phần.

Cấu trúc là một tập hợp các dữ liệu có thể cùng hoặc khác kiểu, được nhóm lại thành một đơn vị.

Để khai báo cấu trúc, bạn sử dụng từ khóa typestruct. Câu lệnh struct định nghĩa kiểu dữ liệu mới, trong đó có một hoặc nhiều thành phần. Từ khóa type đặt tên cho cấu trúc.

package main

import "fmt"

// Khai báo cấu trúc
type Books struct {
    title   string
    author  string
    subject string
    bookId  int
}

func main() {
    // Tạo một cấu trúc mới
    fmt.Println(Books{"Ngôn ngữ Go", "mr.white", "Hướng dẫn Go", 100001})

    // Có thể dùng cú pháp key => value
    fmt.Println(Books{title: "Ngôn ngữ Go", author: "mr.white", subject: "Hướng dẫn Go", bookId: 100002})

    // Các trường bị bỏ qua sẽ có giá trị mặc định
    fmt.Println(Books{title: "Ngôn ngữ Go", author: "mr.white"})
}

2. Truy cập thành phần của cấu trúc

Để truy cập thành phần trong cấu trúc, bạn dùng toán tử dấu chấm ..

package main

import "fmt"

// Khai báo cấu trúc
type Books struct {
    title   string
    author  string
    subject string
    bookId  int
}

func main() {
    var Book1, Book2 Books

    /* Thông tin về sách 1 */
    Book1.title = "Ngôn ngữ Go"
    Book1.author = "mr.white"
    Book1.subject = "Hướng dẫn ngôn ngữ Go"
    Book1.bookId = 100001

    /* Thông tin về sách 2 */
    Book2.title = "Hướng dẫn Python"
    Book2.author = "mr.white"
    Book2.subject = "Hướng dẫn ngôn ngữ Python"
    Book2.bookId = 100002

    /* In thông tin sách 1 */
    fmt.Printf("Tiêu đề sách 1: %s\n", Book1.title)
    fmt.Printf("Tác giả sách 1: %s\n", Book1.author)
    fmt.Printf("Chủ đề sách 1: %s\n", Book1.subject)
    fmt.Printf("ID sách 1: %d\n", Book1.bookId)

    /* In thông tin sách 2 */
    fmt.Printf("Tiêu đề sách 2: %s\n", Book2.title)
    fmt.Printf("Tác giả sách 2: %s\n", Book2.author)
    fmt.Printf("Chủ đề sách 2: %s\n", Book2.subject)
    fmt.Printf("ID sách 2: %d\n", Book2.bookId)
}

3. Truyền cấu trúc vào hàm

Trong Go, bạn có thể truyền cấu trúc vào hàm dưới dạng giá trị hoặc con trỏ.

Khi truyền giá trị cấu trúc vào hàm, bạn đang truyền bản sao của nó. Những thay đổi bên trong hàm sẽ không ảnh hưởng đến cấu trúc gốc.

package main

import "fmt"

// Định nghĩa cấu trúc
type Person struct {
    Name string
    Age  int
}

// Truyền giá trị cấu trúc
func updateAge(p Person) {
    p.Age = 30
    fmt.Println("Trong hàm updateAge:", p)
}

func main() {
    person := Person{Name: "Alice", Age: 25}
    updateAge(person)
    fmt.Println("Sau khi gọi hàm:", person)
}

4. Con trỏ đến cấu trúc

Khi truyền con trỏ cấu trúc vào hàm, bạn đang làm việc trực tiếp với cấu trúc gốc. Mọi thay đổi đều ảnh hưởng đến cấu trúc ban đầu.

package main

import "fmt"

// Định nghĩa cấu trúc
type Person struct {
    Name string
    Age  int
}

// Truyền con trỏ cấu trúc
func updateAge(p *Person) {
    p.Age = 30
    fmt.Println("Trong hàm updateAge:", *p)
}

func main() {
    person := Person{Name: "Alice", Age: 25}
    updateAge(&person)
    fmt.Println("Sau khi gọi hàm:", person)
}

Khi chọn giữa truyền giá trị hay con trỏ, cần cân nhắc:

  • Nếu cấu trúc lớn, dùng con trỏ để tiết kiệm bộ nhớ.
  • Nếu muốn thay đổi cấu trúc trong hàm, phải dùng con trỏ.
  • Nếu chỉ đọc dữ liệu, truyền giá trị an toàn hơn.

Thông thường trong Go, nên dùng con trỏ để truyền cấu trúc, giúp tiết kiệm tài nguyên và tránh sao chép không cần thiết.

II. Slice trong Go

1. Khởi tạo slice

Mảng trong Go có độ dài cố định. Slice (mảng động) cho phép thêm phần tử linh hoạt, có thể mở rộng khi cần.

package main

import "fmt"

func main() {
    // Khởi tạo slice trực tiếp
    s := []int{1, 2, 3}
    fmt.Println("Slice s:", s)

    // Tạo slice từ mảng
    s1 := s[:]
    fmt.Println("Slice s1:", s1)

    // Cắt slice từ chỉ số 1 đến 3
    s2 := s[1:3]
    fmt.Println("Slice s2:", s2)

    // Dùng make để khởi tạo
    s3 := make([]int, 3)
    fmt.Println("Slice s3:", s3)
}

2. Hàm len() và cap()

  • len() trả về số phần tử trong slice.
  • cap() trả về sức chứa tối đa của slice.
package main

import "fmt"

func showSlice(x []int) {
    fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

func main() {
    // Khởi tạo slice với độ dài 3, sức chứa 5
    var numbers = make([]int, 3, 5)
    showSlice(numbers)
}

3. Slice rỗng (nil)

package main

import "fmt"

func showSlice(x []int) {
    fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

func main() {
    // Khởi tạo slice rỗng
    var numbers []int
    showSlice(numbers)

    if numbers == nil {
        fmt.Println("Slice là rỗng")
    }
}

4. Cắt slice

package main

import "fmt"

func showSlice(x []int) {
    fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

func main() {
    // Tạo slice
    numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
    showSlice(numbers)

    // Cắt slice từ index 1 đến 4
    fmt.Println("numbers[1:4] =", numbers[1:4])

    // Mặc định từ đầu đến index 3
    fmt.Println("numbers[:3] =", numbers[:3])

    // Mặc định từ index 4 đến cuối
    fmt.Println("numbers[4:] =", numbers[4:])

    // Tạo slice rỗng với sức chứa 5
    numbers1 := make([]int, 0, 5)
    showSlice(numbers1)

    // Cắt từ đầu đến index 2
    number2 := numbers[:2]
    showSlice(number2)

    // Cắt từ index 2 đến 5
    number3 := numbers[2:5]
    showSlice(number3)
}

5. Hàm append() và copy()

Để tăng kích thước slice, bạn phải tạo một slice mới và sao chép nội dung cũ.

package main

import "fmt"

func showSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

func main() {
var numbers []int
showSlice(numbers)

// Thêm phần tử vào slice rỗng
numbers = append(numbers, 0)
showSlice(numbers)

// Thêm một phần tử
numbers = append(numbers, 1)
showSlice(numbers)

// Thêm nhiều phần tử cùng lúc
numbers = append(numbers, 2, 3, 4)
showSlice(numbers)

// Tạo slice mới với sức chứa gấp đôi
numbers1 := make([]int, len(numbers), cap(numbers)*2)

// Sao chép dữ liệu từ slice cũ sang mới
copy(numbers1, numbers)
showSlice(numbers1)
}

Thẻ: Go struct slice pointer function

Đăng vào ngày 28 tháng 5 lúc 14:46