Срезы и карты содержат указатели на базовые данные, поэтому будьте осторожны со сценариями, когда их нужно скопировать.
Получение срезов и карт
Помните, что пользователи могут изменять карту или срез, полученный вами в качестве аргумента, если вы сохраняете ссылку на него.
Неудачный вариант:
func (d *Driver) SetTrips(trips []Trip) {
d.trips = trips
}
trips := ...
d1.SetTrips(trips)
// Вы хотели изменить d1.trips?
trips[0] = ...
Хороший вариант:
func (d *Driver) SetTrips(trips []Trip) {
d.trips = make([]Trip, len(trips))
copy(d.trips, trips)
}
trips := ...
d1.SetTrips(trips)
// Теперь мы можем изменить trips[0],
// не затрагивая d1.trips.
trips[0] = ...
Возврат срезов и карт
Точно так же будьте осторожны с пользовательскими модификациями карт или срезов, раскрывающих внутреннее состояние.
Неудачный вариант:
type Stats struct {
mu sync.Mutex
counters map[string]int
}
// Snapshot возвращает текущую статистику.
func (s *Stats) Snapshot() map[string]int {
s.mu.Lock()
defer s.mu.Unlock()
return s.counters
}
// snapshot больше не защищен мьютексом, поэтому любой
// доступ к snapshot повод для гонки данных.
snapshot := stats.Snapshot()
Хороший вариант:
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 теперь является копией.
snapshot := stats.Snapshot()
Читайте также:
- Массивы, срезы и строки: механика работы append в Golang
- Срезы в Golang: внутреннее устройство и использование
- Эффективный Go: срезы (slices)
Комментариев нет:
Отправить комментарий