Как сгенерировать случайное число в Swift? (Int, Double, Float, Bool)
Современный способ генерации случайных чисел в Swift (Swift 4.2+)
Начиная с Swift 4.2 (вышла в 2018 году), в стандартную библиотеку была добавлена встроенная поддержка генерации случайных чисел. Вам больше не нужно использовать arc4random(), drand48() или другие C-функции. Всё делается через статические методы на самих типах.
1. Случайное целое число (Int)
Для генерации случайного Int в заданном диапазоне используйте метод random(in:):
// Случайное число от 1 до 10 включительно
let randomInt = Int.random(in: 1...10)
print(randomInt) // Например: 7
// Случайное число от 0 до 100 (не включая 100)
let randomIntHalfOpen = Int.random(in: 0..<100)
print(randomIntHalfOpen) // Например: 42
2. Случайное число с плавающей точкой (Double, Float)
Работает аналогично, но диапазон может быть дробным:
// Случайный Double от 0.0 до 1.0
let randomDouble = Double.random(in: 0...1)
print(randomDouble) // Например: 0.54321
// Случайный Float от -10.0 до 10.0
let randomFloat = Float.random(in: -10.0...10.0)
print(randomFloat) // Например: 3.14159
// Случайный CGFloat (часто используется в UIKit)
import CoreGraphics
let randomCGFloat = CGFloat.random(in: 0...1)
3. Случайное булево значение (Bool)
Для Bool есть специальный метод random():
let randomBool = Bool.random()
print(randomBool) // true или false с вероятностью 50%
4. Случайный элемент из коллекции
Это очень удобно для массивов и других коллекций:
let colors = ["red", "green", "blue", "yellow"]
if let randomColor = colors.randomElement() {
print(randomColor) // Например: "green"
}
// Для массивов с опциональными элементами
let numbers = [1, 2, 3, 4, 5]
let randomNumber = numbers.randomElement()! // Опционально, но если массив не пуст — безопасно
5. Перемешивание массива (shuffle)
Если нужно случайно перемешать элементы:
var deck = [1, 2, 3, 4, 5, 6]
deck.shuffle()
print(deck) // Например: [3, 6, 1, 5, 2, 4]
// Или получить новую перемешанную копию:
let shuffledDeck = deck.shuffled()
Важные замечания
- Безопасность типов:
random(in:)возвращает значение того же типа, к которому вы его применяете. Никаких приведенийUInt32кInt. - Криптостойкость: Стандартный генератор
SystemRandomNumberGenerator(используется по умолчанию) является криптографически безопасным. Для обычных задач этого более чем достаточно. - Воспроизводимость: Если вам нужны повторяемые последовательности (например, для тестов), можно создать свой генератор, реализующий протокол
RandomNumberGenerator.
Пример: создание генератора для тестов
struct SeededGenerator: RandomNumberGenerator {
var state: UInt64
mutating func next() -> UInt64 {
state = state &* 6364136223846793005 &+ 1442695040888963407
return state
}
}
var generator = SeededGenerator(state: 42)
let testInt = Int.random(in: 1...100, using: &generator)
let testDouble = Double.random(in: 0...1, using: &generator)
Таким образом, забудьте про arc4random — используйте .random(in:) и .randomElement(). Это современно, безопасно и удобно.
Альтернативный подход: использование GameplayKit для более сложной рандомизации
Если вам нужно больше контроля над распределением случайных чисел (например, нормальное распределение, гауссово шумоподавление или генерация случайных чисел с определённой вероятностью), обратите внимание на фреймворк GameplayKit (импортируется как import GameplayKit).
Пример с равномерным распределением:
import GameplayKit
let randomSource = GKRandomSource()
let randomInt = randomSource.nextInt(upperBound: 10) // 0..<10
let randomIntInRange = randomSource.nextInt(in: 1...10)
Для гауссова распределения:
let gaussianSource = GKGaussianDistribution(randomSource: GKRandomSource(), mean: 0.0, deviation: 1.0)
let sample = gaussianSource.nextUniform() // -1...1, с пиком около 0
Также можно создать детерминированный источник для повторяемых последовательностей:
let fixedSeed = GKLinearCongruentialRandomSource(seed: 12345)
let value1 = fixedSeed.nextInt(upperBound: 100) // Всегда будет одинаково при старте с seed 12345
Когда это полезно? В играх, симуляциях, генерации уровней или тестовых данных, где нужно предсказуемое "случайное" поведение. Для 90% задач стандартного .random(in:) более чем достаточно.