Giá trị zero và giá trị mặc định
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 17 trên 107.
Trong Go, mỗi biến đều có giá trị không: giá trị mặc định được gán khi bạn khai báo biến mà không khởi tạo rõ ràng. Hiểu về giá trị không rất cần thiết khi làm việc với struct, vì các trường chưa được khởi tạo sẽ tự động nhận những giá trị mặc định này.
Mỗi kiểu dữ liệu có giá trị mặc định riêng:
| Kiểu dữ liệu | Giá trị mặc định |
|---|---|
| int, float64 | 0 |
| string | "" (chuỗi rỗng) |
| bool | false |
| pointer, slice, map | nil |
Khi tạo một struct, mọi trường bạn không đặt giá trị một cách rõ ràng sẽ nhận giá trị không.
type User struct {
Name string
Age int
Active bool
}
func main() {
var u User
fmt.Println(u.Name) // "" (chuỗi rỗng)
fmt.Println(u.Age) // 0
fmt.Println(u.Active) // false
}Điều này cũng áp dụng cho việc khởi tạo một phần. Chỉ các trường bạn chỉ định mới nhận giá trị tùy chỉnh.
u := User{Name: "Alice"}
fmt.Println(u.Age) // 0
fmt.Println(u.Active) // false
Giá trị không giúp bạn dùng struct ngay mà không cần khởi tạo tường minh. Tuy nhiên, hãy cẩn thận với các kiểu tham chiếu như slice và map. Giá trị không của chúng là nil, điều này có thể gây ra panic khi chạy nếu bạn cố dùng chúng mà không khởi tạo.
Thử thách
DễHãy xây dựng một hệ thống hồ sơ người chơi để minh họa cách giá trị không (zero value) hoạt động trong Go. Bạn sẽ tạo hồ sơ trò chơi, trong đó một số trường được thiết lập rõ ràng, còn những trường khác dùng giá trị không mặc định.
Bạn sẽ sắp xếp code trong hai tệp:
player.go: Định nghĩa một cấu trúcPlayervới các trường sau:Username(chuỗi),Level(số nguyên),Score(số nguyên),IsPremium(bool) vàGuildName(chuỗi). Đồng thời tạo phương thứcDisplayProfiletrả về một chuỗi đã định dạng, hiển thị toàn bộ thông tin của người chơi.main.go: Đọc tên người dùng từ đầu vào và tạo một Player bằng cách khởi tạo một phần: chỉ thiết lập trườngUsername. Sau đó hiển thị hồ sơ đầy đủ để xem Go điền các giá trị không vào những trường chưa được thiết lập như thế nào.
Đầu vào sẽ có định dạng như sau:
- Dòng 1: Tên người dùng của người chơi
Phương thức DisplayProfile của bạn sẽ trả về một chuỗi theo đúng định dạng sau:
Username: [Username]
Level: [Level]
Score: [Score]
Premium: [IsPremium]
Guild: [GuildName]Ví dụ, nếu tên người dùng là ShadowKnight, đầu ra sẽ hiển thị tên người dùng cùng với tất cả giá trị không của những trường chưa được khởi tạo:
Username: ShadowKnight
Level: 0
Score: 0
Premium: false
Guild: Lưu ý trường Guild không hiển thị gì sau dấu hai chấm: đó là giá trị không của chuỗi rỗng. Thử thách này giúp bạn thấy chính xác Go gán giá trị nào cho từng kiểu khi bạn không cung cấp giá trị cụ thể.
Tự làm thử
package main
import (
"fmt"
)
func main() {
// Đọc tên người dùng từ đầu vào
var username string
fmt.Scanln(&username)
// TODO: Tạo Player bằng cách chỉ khởi tạo một phần
// Chỉ gán giá trị cho trường Username, để các trường khác giữ giá trị zero
// TODO: Hiển thị hồ sơ người chơi bằng phương thức DisplayProfile
}
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