← Danh sách bài học Bài 10/20

🏗️ Bài 10: Struct (Cấu Trúc Dữ Liệu)

⏱️ 25 phút | 📚 Trung bình

🎯 Mục tiêu:

1. Struct Là Gì?

Struct gom nhóm các dữ liệu liên quan thành một kiểu mới. Giống class trong OOP nhưng đơn giản hơn.

// Định nghĩa struct
type Person struct {
    Name string
    Age  int
    City string
}

func main() {
    // Tạo instance
    person1 := Person{
        Name: "Minh",
        Age:  25,
        City: "Hà Nội",
    }
    
    fmt.Println(person1.Name)  // Minh
    fmt.Println(person1.Age)   // 25
}

2. Các Cách Tạo Struct

type User struct {
    Name  string
    Email string
    Age   int
}

// Cách 1: Named fields (rõ ràng nhất)
u1 := User{Name: "Minh", Email: "minh@email.com", Age: 25}

// Cách 2: Không cần tên field (theo thứ tự)
u2 := User{"Lan", "lan@email.com", 22}

// Cách 3: Khai báo trước, gán sau
var u3 User
u3.Name = "Huy"
u3.Email = "huy@email.com"
u3.Age = 28

// Cách 4: new() - trả về pointer
u4 := new(User)
u4.Name = "Mai"
💡 Best Practice: Dùng cách 1 (named fields) để code rõ ràng hơn.

3. Methods Trên Struct

Method là hàm gắn với struct.

type Rectangle struct {
    Width  float64
    Height float64
}

// Method tính diện tích
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// Method tính chu vi
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func main() {
    rect := Rectangle{Width: 10, Height: 5}
    fmt.Println("Diện tích:", rect.Area())      // 50
    fmt.Println("Chu vi:", rect.Perimeter())    // 30
}

4. Pointer Receiver vs Value Receiver

type Counter struct {
    Value int
}

// Value receiver - COPY, không thay đổi gốc
func (c Counter) IncrementCopy() {
    c.Value++  // Chỉ thay đổi bản copy
}

// Pointer receiver - thay đổi trực tiếp
func (c *Counter) Increment() {
    c.Value++  // Thay đổi gốc
}

func main() {
    counter := Counter{Value: 0}
    
    counter.IncrementCopy()
    fmt.Println(counter.Value)  // 0 (không đổi)
    
    counter.Increment()
    fmt.Println(counter.Value)  // 1 (đã tăng)
}

5. Embedded Structs (Nhúng Struct)

type Address struct {
    City    string
    Country string
}

type Employee struct {
    Name    string
    Address  // Embedded - không cần tên field
}

func main() {
    emp := Employee{
        Name: "Minh",
        Address: Address{
            City:    "Hà Nội",
            Country: "Việt Nam",
        },
    }
    
    // Truy cập trực tiếp (promoted fields)
    fmt.Println(emp.City)     // Hà Nội
    fmt.Println(emp.Country)  // Việt Nam
}

📝 Tóm Tắt