Structs
1. Structs là gì?
Struct (structure) trong Go là một kiểu dữ liệu do người dùng định nghĩa, dùng để nhóm các trường dữ liệu (fields) lại với nhau để biểu diễn một thực thể có ý nghĩa.
Struct tương tự như các lớp (class) trong các ngôn ngữ hướng đối tượng, nhưng Go không có khái niệm kế thừa hay đa hình như OOP truyền thống.
Ví dụ cơ bản:
2. Cú pháp và cách khai báo Structs
Struct được khai báo bằng từ khóa
type
vàstruct
.Các trường (fields) có thể thuộc bất kỳ kiểu dữ liệu nào (bao gồm cả struct khác, con trỏ, slice, map, v.v.).
Cú pháp:
Ví dụ với các kiểu dữ liệu khác nhau:
3. Khởi tạo Struct
Có nhiều cách để khởi tạo một struct:
3.1. Khởi tạo trực tiếp với giá trị
3.2. Khởi tạo không đầy đủ (zero value)
Nếu không gán giá trị, các trường sẽ nhận giá trị mặc định (zero value):
int
: 0string
: ""bool
: falsepointer
: nilslice/map
: nil
3.3. Sử dụng con trỏ
3.4. Khởi tạo với new
Lưu ý: new(Person)
trả về một con trỏ (*Person
) và tất cả các trường được khởi tạo với zero value.
4. Truy cập và sửa đổi trường của Struct
Truy cập trường bằng dấu chấm (
.
).Nếu là con trỏ, Go tự động giải tham chiếu (
*p.Name
tương đương vớip.Name
).
Ví dụ:
5. Struct lồng nhau (Nested Structs)
Struct có thể chứa các struct khác để biểu diễn các mối quan hệ phức tạp.
Ví dụ:
6. Anonymous Structs (Struct ẩn danh)
Struct ẩn danh được khai báo mà không cần đặt tên, thường dùng cho các trường hợp sử dụng tạm thời.
Ví dụ:
Ứng dụng thực tế: Anonymous structs thường được dùng trong JSON unmarshalling hoặc khi trả về dữ liệu tạm thời.
7. Struct với Method
Go hỗ trợ gắn các method vào struct để thêm hành vi, tương tự như các phương thức trong OOP.
Ví dụ:
Receiver:
r Rectangle
là tham số nhận struct.Pointer Receiver: Nếu muốn thay đổi giá trị của struct, sử dụng con trỏ (
*Rectangle
).
Ví dụ với Pointer Receiver:
Khi nào dùng Pointer Receiver?
Khi cần thay đổi giá trị của struct.
Khi struct lớn, tránh sao chép để tối ưu hiệu năng.
8. Tags trong Struct
Struct có thể gắn tags để cung cấp metadata, thường dùng trong JSON, database, hoặc các thư viện khác.
Ví dụ:
Ứng dụng thực tế:
Tags được dùng nhiều trong:
JSON encoding/decoding (
encoding/json
).Validation (thư viện như
github.com/go-playground/validator
).ORM (như
gorm.io/gorm
).
9. So sánh Struct
Struct có thể được so sánh bằng toán tử
==
hoặc!=
nếu tất cả các trường đều là comparable.
Ví dụ:
Lưu ý:
Nếu struct chứa các trường không comparable (như slice, map, function), bạn không thể so sánh trực tiếp.
Để so sánh phức tạp, hãy viết hàm riêng hoặc dùng thư viện như
github.com/google/go-cmp
.
10. Struct và Concurrency
Khi sử dụng struct trong môi trường đa luồng (goroutines), bạn cần cẩn thận với data race.
Ví dụ sai:
Cách sửa: Sử dụng mutex để bảo vệ dữ liệu:
11. Tối ưu hóa Struct
Một Senior Golang developer luôn chú ý đến hiệu năng khi thiết kế struct:
11.1. Sắp xếp trường để giảm memory padding
Go sắp xếp các trường trong struct để tối ưu hóa bộ nhớ, nhưng thứ tự khai báo có thể gây lãng phí (padding).
Ví dụ không tối ưu:
Kích thước của BadStruct
có thể là 24 bytes do padding.
Cách tối ưu:
Kích thước của GoodStruct
là 16 bytes.
Mẹo: Sắp xếp các trường từ lớn đến nhỏ (int64, int32, int8, bool, v.v.).
11.2. Tránh sao chép struct lớn
Nếu struct lớn, hãy truyền con trỏ (
*Struct
) thay vì giá trị để tránh sao chép tốn tài nguyên.
11.3. Sử dụng embedded struct để tái sử dụng
Go hỗ trợ embedding để nhúng một struct vào struct khác, giúp tái sử dụng các trường và phương thức.
Ví dụ:
12. Ứng dụng thực tế của Struct
Struct được sử dụng rộng rãi trong:
API: Biểu diễn request/response (JSON).
Database: Map dữ liệu từ SQL/NoSQL (thư viện như GORM).
Configuration: Lưu trữ cấu hình ứng dụng.
Concurrency: Quản lý trạng thái trong goroutines.
Ví dụ thực tế với API:
13. Những lỗi thường gặp với Struct
Sao chép struct lớn: Gây tốn bộ nhớ và CPU.
Quên mutex trong concurrency: Dẫn đến data race.
Sử dụng zero value không mong muốn: Ví dụ, quên khởi tạo con trỏ hoặc slice.
Tag không đúng: Gây lỗi khi encode/decode JSON hoặc mapping database.
Không tối ưu memory alignment: Gây lãng phí bộ nhớ.
15. Tài liệu tham khảo
Thư viện hỗ trợ:
encoding/json
,github.com/go-playground/validator
,gorm.io/gorm
.
Last updated