Struct lồng nhau
Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 16 trên 107.
struct lồng nhau là một struct chứa một struct có tên khác làm một trong các trường của nó. Cách này giúp bạn mô hình hóa dữ liệu phức tạp, có cấu trúc phân cấp bằng cách kết hợp các kiểu nhỏ hơn có thể tái sử dụng.
type Address struct {
Street string
City string
ZIP string
}
type Person struct {
Name string
Age int
Address Address // struct lồng nhau
}Để truy cập các trường trong struct lồng nhau, bạn nối tên các trường bằng dấu chấm.
p := Person{
Name: "Alice",
Age: 30,
Address: Address{
Street: "123 Main St",
City: "Boston",
ZIP: "02101",
},
}
fmt.Println(p.Address.City) // BostonLồng ghép giúp tái sử dụng code. Kiểu Address có thể được dùng trong nhiều struct như Person, Company hoặc Order mà không cần lặp lại các trường. Cách làm này phản ánh các mối quan hệ trong thế giới thực, nơi các thực thể chứa những thực thể khác.
type Company struct {
Name string
Employees int
Address Address // Tái sử dụng cùng kiểu Address
}Bạn có thể lồng các struct nhiều cấp, dù giữ cấu trúc phân cấp nông sẽ giúp code dễ đọc hơn. Struct lồng nhau là nền tảng để xây dựng các mô hình dữ liệu hướng đối tượng trong Go.
Thử thách
DễHãy xây dựng một hệ thống quản lý nhân viên để minh họa cách các struct lồng nhau giúp mô hình hóa hệ thống phân cấp trong thực tế. Bạn sẽ tạo một cấu trúc trong đó nhân viên thuộc các phòng ban, còn phòng ban có thông tin về địa điểm.
Bạn sẽ sắp xếp code trong hai tệp:
models.go: Định nghĩa ba struct phối hợp với nhau:Locationcó các trườngBuilding(chuỗi) vàFloor(số nguyên)Departmentcó trườngName(chuỗi) và trườngLocationlồng bên trongEmployeecó các trườngID(số nguyên),Name(chuỗi) và trườngDepartmentlồng bên trong
main.go: Đọc thông tin nhân viên từ đầu vào, tạo một Employee với các struct được lồng đúng cách, rồi hiển thị hồ sơ nhân viên đầy đủ bằng cách truy cập các trường trong cấu trúc lồng nhau.
Đầu vào sẽ có các dòng sau:
- Dòng 1: Mã nhân viên (số nguyên)
- Dòng 2: Tên nhân viên
- Dòng 3: Tên phòng ban
- Dòng 4: Tên tòa nhà
- Dòng 5: Số tầng (số nguyên)
Định dạng đầu ra:
Employee: [Name] (ID: [ID])
Department: [DepartmentName]
Location: [Building], Floor [Floor]Ví dụ, với các giá trị 101, Alice Chen, Engineering, Tower A và 5, đầu ra sẽ là:
Employee: Alice Chen (ID: 101)
Department: Engineering
Location: Tower A, Floor 5Truy cập các trường lồng nhau bằng ký hiệu dấu chấm để lần theo thứ bậc của struct (ví dụ: employee.Department.Location.Building).
Tự làm thử
package main
import "fmt"
func main() {
// Đọc thông tin nhân viên
var id int
var name string
var deptName string
var building string
var floor int
fmt.Scanln(&id)
fmt.Scanln(&name)
fmt.Scanln(&deptName)
fmt.Scanln(&building)
fmt.Scanln(&floor)
// TODO: Tạo một Employee với các struct lồng nhau đúng cách
// Dùng các struct Location, Department và Employee trong models.go
// Khởi tạo tất cả các trường lồng nhau bằng các giá trị đầu vào
// TODO: In ra hồ sơ nhân viên theo định dạng:
// Employee: [Name] (ID: [ID])
// Department: [DepartmentName]
// Location: [Building], Floor [Floor]
// Truy cập các trường lồng nhau bằng dấu chấm (ví dụ: employee.Department.Location.Building)
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng OOP trong Go
Tệp bên ngoàiWorkspace và module trong GoPackage và importTên được export và không được exportGiới thiệu về OOP trong GoStruct như lớpĐịnh nghĩa phương thức cho structReceiver kiểu con trỏ và kiểu giá trịKhởi tạo structHàm khởi tạoÔn tập: máy tính đơn giản4Interface
Giới thiệu về interfaceTriển khai ngầm địnhInterface như một hợp đồngInterface rỗng (any)Khẳng định kiểuswitch kiểuKết hợp interfaceInterface Stringer và ErrorÔn tập: Máy tính hình học7Tính đóng gói
Trường được xuất và không được xuấtĐóng gói ở cấp packagePhương thức getter và setterẨn thông tin trong GoÔn tập: hồ sơ học sinh10Generics (Go 1.18 trở lên)
Giới thiệu về GenericsTham số kiểuRàng buộc kiểuStruct tổng quátGiải pháp thay thế cho phương thức tổng quátÔn tập: tập hợp tổng quát13Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếMẫu SingletonMẫu FactoryMẫu Abstract FactoryMẫu ObserverMẫu Strategy2Tìm hiểu chuyên sâu về kiểu dữ liệu và struct
Kiểu cơ bản và kiểu tổng hợpĐịnh nghĩa kiểu dữ liệu tùy chỉnhThẻ structStruct ẩn danhStruct lồng nhauGiá trị zero và giá trị mặc địnhÔn tập: sổ liên lạc5Ưu tiên kết hợp hơn kế thừa
Vì sao Go không có kế thừaNhập môn nhúng structTự động nâng phương thứcNhúng nhiều structNhúng và kết tậpChe khuất phương thức được nhúngÔn tập: hệ phân cấp nhân viên8Xử lý lỗi và lập trình hướng đối tượng
Giao diện errorCác kiểu lỗi tùy chỉnhBọc lỗi với fmt.ErrorfLỗi sentinelerrors.Is() và errors.As()Panic, defer và recoverÔn tập: trình phân tích tệp3Con trỏ và bộ nhớ
Cơ bản về con trỏ trong GoCon trỏ đến structTruyền theo giá trị và tham chiếuHàm new()Thu gom rác trong GoÔn tập: xây dựng danh sách liên kết6Đa hình trong Go
Đa hình qua interfaceĐịnh kiểu vịt trong GoQuy tắc thỏa mãn interfaceCác tập hợp đa hìnhTiêm phụ thuộcÔn tập: bộ xử lý thanh toán9Lập trình đồng thời và lập trình hướng đối tượng
Cơ bản về goroutineChannel và giao tiếpChannel có bộ đệm và không có bộ đệmCâu lệnh selectsync.Mutex và sync.RWMutexsync.WaitGroupThiết kế struct an toàn luồngÔn tập: worker poolTự luyện tập: Trình biên dịch Go online