Nhận Slice và Map
Hãy nhớ rằng khi một map hoặc một slice được truyền như một tham số của hàm, nếu bạn lưu trữ một tham chiếu đến chúng, người dùng có thể sửa đổi chúng.
Phương pháp không được khuyến nghị:
func (d *Driver) SetTrips(trips []Trip) {
d.trips = trips
}
trips := ...
d1.SetTrips(trips)
// Bạn có đang cố gắng sửa đổi d1.trips không?
trips[0] = ...
Phương pháp được khuyến nghị:
func (d *Driver) SetTrips(trips []Trip) {
d.trips = make([]Trip, len(trips))
copy(d.trips, trips)
}
trips := ...
d1.SetTrips(trips)
// Ở đây chúng ta sửa đổi trips[0], nhưng nó sẽ không ảnh hưởng đến d1.trips
trips[0] = ...
Trả về Slice hoặc Map
Tương tự, hãy chú ý đến việc người dùng sửa đổi một map hoặc slice mà tiết lộ trạng thái nội bộ.
Phương pháp không được khuyến nghị:
type Stats struct {
mu sync.Mutex
counters map[string]int
}
// Snapshot trả về trạng thái hiện tại
func (s *Stats) Snapshot() map[string]int {
s.mu.Lock()
defer s.mu.Unlock()
return s.counters
}
// snapshot không còn được bảo vệ bởi mutex
// vì vậy mọi truy cập vào snapshot sẽ chịu sự cạnh tranh dữ liệu và ảnh hưởng đến stats.counters
snapshot := stats.Snapshot()
Phương pháp được khuyến nghị:
type Stats struct {
mu sync.Mutex
counters map[string]int
}
func (s *Stats) Snapshot() map[string]int {
s.mu.Lock()
defer s.mu.Unlock()
result := make(map[string]int, len(s.counters))
for k, v := range s.counters {
result[k] = v
}
return result
}
// snapshot giờ đây là một bản sao
snapshot := stats.Snapshot()