← Danh sách bài học
Bài 10/20
🏗️ Bài 10: Struct (Cấu Trúc Dữ Liệu)
🎯 Mục tiêu:
- Hiểu Struct và tại sao cần nó
- Khai báo và tạo instance
- Methods trên struct
- Embedded structs
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: "[email protected]", Age: 25}
// Cách 2: Không cần tên field (theo thứ tự)
u2 := User{"Lan", "[email protected]", 22}
// Cách 3: Khai báo trước, gán sau
var u3 User
u3.Name = "Huy"
u3.Email = "[email protected]"
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
type Name struct { fields }- Truy cập field:
instance.FieldName - Method:
func (r Receiver) Method() - Pointer receiver
*Typethay đổi gốc - Embedded: struct trong struct được promoted