Bài học theo mô-đun (5/5)
Mẫu hàm tạo `Mới...`
Cờ vây không có từ khóa constructor. Hội nghị là một nhà máy
hàm trả về giá trị hoặc con trỏ được khởi tạo đúng cách. Bởi
tên thường được gọi là NewT (hoặc NewXxx).
Mẫu cơ sở: NewT
type User struct {
Name string
Age int
}
func NewUser(name string, age int) *User {
return &User{Name: name, Age: age}
}
u := NewUser("Ada", 36)
fmt.Println(u.Name)Lợi ích so với nghĩa đen trực tiếp &User{...}:
- Bạn tập trung xác thực và mặc định.
- Bạn có thể có các trường chưa được xuất và chỉ điền chúng từ hàm tạo.
- Bạn có thể thay đổi cách thực hiện mà không làm gián đoạn người gọi.
Trình xây dựng có xác thực: (*T, error)
Khi quá trình khởi tạo có thể không thành công, hãy trả về (*T, error):
import "errors"
func NewUser(name string, age int) (*User, error) {
if name == "" {
return nil, errors.New("nome obbligatorio")
}
if age < 0 {
return nil, errors.New("eta non valida")
}
return &User{Name: name, Age: age}, nil
}
u, err := NewUser("Ada", 36)
if err != nil {
// handle...
}Đây là mẫu thành ngữ cho bất kỳ hàm tạo nào có điều kiện tiên quyết: kết nối db, xử lý tệp, cấu hình máy chủ, v.v.
Nhiều hàm tạo
Nếu bạn có nhiều "cách" để xây dựng, hãy sử dụng tên mô tả:
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }Không bị quá tải trong Go: tên không rõ ràng.
Tùy chọn chức năng (cái nhìn nâng cao)
Khi có nhiều tham số tùy chọn, mẫu thành ngữ là "tùy chọn chức năng":
type Option func(*Server)
func WithPort(p int) Option {
return func(s *Server) { s.Port = p }
}
func WithTLS(cert, key string) Option {
return func(s *Server) { s.Cert, s.Key = cert, key }
}
func NewServer(opts ...Option) *Server {
s := &Server{Port: 8080} // default
for _, opt := range opts {
opt(s)
}
return s
}
s := NewServer(WithPort(9000), WithTLS("c.pem", "k.pem"))Nó dài dòng hơn nghĩa đen nhưng có tỷ lệ phù hợp với nhiều tùy chọn
tham số và duy trì khả năng tương thích ngược (thêm Option mới
không phá vỡ người gọi hiện tại).
Khi bạn KHÔNG cần một hàm tạo
Nếu giá trị 0 của loại đã hữu ích, hãy để người gọi sử dụng
nghĩa đen trực tiếp. Ví dụ chuẩn: sync.Mutex không có hàm tạo,
var m sync.Mutex đã là một mutex sẵn sàng sử dụng. Tương tự cho bytes.Buffer.
Quy tắc là: "Làm cho giá trị 0 trở nên hữu ích". Nếu bạn có thể thì không hàm tạo bắt buộc.
Hãy thử nó
Viết hàm xuất xưởng NewUser(name string, age int) *User trả về &User{Name: name, Age: age}.
Hiển thị gợi ý
Sử dụng `&User{...}` theo nghĩa đen để trả về một con trỏ.
Giải pháp khả dụng sau 3 lần thử
Biến Người dùng mới thành (chuỗi tên) (*Người dùng, lỗi): if name == '' return nil,errors.New('nome obbligatorio').
Hiển thị gợi ý
Nếu có điều kiện tiên quyết, hãy trả về (*T, lỗi) và trả về nil + lỗi khi thất bại.
Giải pháp khả dụng sau 3 lần thử
Quy ước thành ngữ dành cho các hàm tạo trong Go là gì?
// Which signature is more idiomatic?Tóm tắt lại
- Không
constructor: sử dụng hàmNewT(hoặcNewbên trong gói cùng tên). - Trả về
*Tđối với trường hợp đơn giản;(*T, error)với điều kiện tiên quyết hoặc xác thực. - Khi có lỗi: trả về
nillàm con trỏ và lỗi giải thích làm giá trị thứ hai. - Không quá tải; sử dụng tên mô tả (
NewUserFromJSON,NewAdmin). - "Làm cho giá trị 0 trở nên hữu ích": nếu có thể thì hàm tạo là không cần thiết.
- Mẫu nâng cao cho nhiều tham số tùy chọn: tùy chọn chức năng.