Тип rand.Rand
Тип rand.Rand представляет собой генератор
псевдослучайных чисел, который хранит собственное
состояние. Это позволяет создавать несколько
независимых генераторов с разными начальными
значениями. В отличие от глобального генератора,
использование собственного экземпляра rand.Rand
дает контроль над последовательностью случайных
чисел и позволяет получать воспроизводимые
результаты при одинаковом начальном значении.
Создание экземпляра
Для создания нового генератора используется
функция rand.New, которая принимает
источник rand.Source. Обычно в качестве
источника используют rand.NewSource с
указанным начальным значением:
package main
import (
"fmt"
"math/rand"
)
func main() {
source := rand.NewSource(42)
r := rand.New(source)
fmt.Println(r.Intn(100))
}
Результат выполнения кода:
"81"
Методы генерации чисел
Экземпляр rand.Rand предоставляет методы
для генерации различных типов случайных чисел:
package main
import (
"fmt"
"math/rand"
)
func main() {
r := rand.New(rand.NewSource(1))
fmt.Println(r.Int()) // случайное int
fmt.Println(r.Intn(100)) // int от 0 до 99
fmt.Println(r.Int31()) // случайное int32
fmt.Println(r.Int63()) // случайное int64
fmt.Println(r.Float64()) // float64 от 0.0 до 1.0
fmt.Println(r.Float32()) // float32 от 0.0 до 1.0
fmt.Println(r.Uint32()) // случайное uint32
fmt.Println(r.Uint64()) // случайное uint64
}
Результат выполнения кода:
"5577006791947779410"
"81"
"1298498081"
"5577006791947779410"
"0.6046602879796196"
"0.6046603"
"1298498081"
"5577006791947779410"
Воспроизводимость результатов
При использовании одного и того же начального значения генератор всегда выдает одинаковую последовательность чисел. Это полезно для тестирования и отладки:
package main
import (
"fmt"
"math/rand"
)
func main() {
r1 := rand.New(rand.NewSource(10))
r2 := rand.New(rand.NewSource(10))
fmt.Println(r1.Intn(1000))
fmt.Println(r2.Intn(1000))
fmt.Println(r1.Intn(1000))
fmt.Println(r2.Intn(1000))
}
Результат выполнения кода:
"81"
"81"
"887"
"887"
Независимость генераторов
Каждый экземпляр rand.Rand работает
независимо от других. Это позволяет использовать
разные генераторы в разных частях программы
без взаимного влияния:
package main
import (
"fmt"
"math/rand"
)
func main() {
rA := rand.New(rand.NewSource(100))
rB := rand.New(rand.NewSource(200))
fmt.Println(rA.Intn(100))
fmt.Println(rB.Intn(100))
fmt.Println(rA.Intn(100))
fmt.Println(rB.Intn(100))
}
Результат выполнения кода:
"69"
"8"
"5"
"91"
Методы для работы со слайсами
Тип rand.Rand также предоставляет методы
для перемешивания элементов слайса и генерации
перестановок:
package main
import (
"fmt"
"math/rand"
)
func main() {
r := rand.New(rand.NewSource(5))
// Перемешивание слайса
slice := []int{1, 2, 3, 4, 5}
r.Shuffle(len(slice), func(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
})
fmt.Println(slice)
// Генерация перестановки
perm := r.Perm(5)
fmt.Println(perm)
}
Результат выполнения кода:
"[2 3 5 1 4]"
"[2 3 1 0 4]"
Потокобезопасность
Важно помнить, что экземпляры rand.Rand
не являются потокобезопасными. При использовании
в нескольких горутинах необходимо синхронизировать
доступ с помощью мьютекса или использовать
отдельные генераторы для каждой горутины:
package main
import (
"fmt"
"math/rand"
"sync"
)
func main() {
var mu sync.Mutex
r := rand.New(rand.NewSource(1))
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
val := r.Intn(100)
mu.Unlock()
fmt.Println(val)
}()
}
wg.Wait()
}
Смотрите также
-
функцию
rand.New,
которая создает новый генератор случайных чисел -
функцию
rand.NewSource,
которая создает источник случайных чисел -
функцию
rand.Intn,
которая генерирует случайное число от 0 до n-1 -
функцию
rand.Perm,
которая возвращает перестановку чисел от 0 до n-1