Метод sync.Map.Swap

Метод sync.Map.Swap атомарно заменяет значение, связанное с указанным ключом, на новое значение и возвращает предыдущее значение (если оно было) и булев флаг, указывающий на наличие ключа в мапе. Этот метод особенно полезен в конкурентной среде, где несколько горутин могут одновременно изменять данные. Первый параметр — ключ для замены, второй — новое значение.

Синтаксис

gom.Swap(key, value)

Метод возвращает два значения: предыдущее значение (тип any) и булев флаг (тип bool). Флаг равен true, если ключ существовал в мапе, и false в противном случае.

Пример

Давайте заменим значение по ключу "a" в мапе и проверим результат:

gopackage main

import (
  "fmt"
  "sync"
)

func main() {
  var m sync.Map

  // Добавляем начальные значения
  m.Store("a", 1)
  m.Store("b", 2)

  // Заменяем значение по ключу "a" с 1 на 10
  old, loaded := m.Swap("a", 10)
  fmt.Printf("old=%v, loaded=%v\n", old, loaded)

  // Проверяем новое значение
  val, _ := m.Load("a")
  fmt.Println(val)
}

Результат выполнения кода:

go"old=1, loaded=true"
"10"

Пример

Рассмотрим случай, когда ключа нет в мапе:

gopackage main

import (
  "fmt"
  "sync"
)

func main() {
  var m sync.Map

  // Пытаемся заменить значение по ключу "x", которого нет
  old, loaded := m.Swap("x", 100)
  fmt.Printf("old=%v, loaded=%v\n", old, loaded)

  // Проверяем, что значение добавилось
  val, ok := m.Load("x")
  fmt.Printf("val=%v, ok=%v\n", val, ok)
}

Результат выполнения кода:

go"old=<nil>, loaded=false"
"val=100, ok=true"

Пример

Использование метода Swap в конкурентной среде с несколькими горутинами:

gopackage main

import (
  "fmt"
  "sync"
)

func main() {
  var m sync.Map
  var wg sync.WaitGroup

  // Инициализация мапы
  m.Store("counter", 0)

  // Запускаем 10 горутин, которые атомарно заменяют значение
  for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(id int) {
      defer wg.Done()
      old, _ := m.Swap("counter", id)
      fmt.Printf("goroutine %d: old=%v\n", id, old)
    }(i)
  }

  wg.Wait()
  val, _ := m.Load("counter")
  fmt.Printf("final value: %v\n", val)
}

Результат выполнения кода (порядок может отличаться):

go"goroutine 3: old=0"
"goroutine 2: old=3"
"goroutine 1: old=2"
"goroutine 0: old=1"
"goroutine 5: old=0"
"goroutine 4: old=5"
"goroutine 7: old=4"
"goroutine 6: old=7"
"goroutine 8: old=6"
"goroutine 9: old=8"
"final value: 9"

Смотрите также

  • метод sync.Map.Store,
    который сохраняет значение по ключу в мапе
  • метод sync.Map.Load,
    который загружает значение по ключу из мапы
  • метод sync.Map.LoadOrStore,
    который загружает или сохраняет значение
  • метод sync.Map.Delete,
    который удаляет значение по ключу из мапы