Напишите обёртку свойства @Clamped, удерживающую значение в диапазоне
Реализуйте обёртку свойства @Clamped, ограничивающую хранимое значение закрытым диапазоном, переданным в атрибуте.
Ограничения:
- Значение, заданное в месте объявления, тоже должно зажиматься, а не только последующие записи.
- Чтение свойства возвращает зажатое значение.
- Не полагайтесь на наблюдатель
didSet.
@propertyWrapper
struct Clamped<Value: Comparable> {
// храните диапазон и backing-значение
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
// ваш код здесь
}
var wrappedValue: Value {
// ваш код здесь
}
}
struct Player {
@Clamped(0...100) var health: Int = 120 // должно стать 100
}
Допишите реализацию.
Структура с @propertyWrapper хранит ClosedRange и backing-значение; setter её wrappedValue зажимает через min(max(...)), и init зажимает начальное значение. Любая запись загоняется обратно в диапазон.
- ✗Забывают зажать начальное значение, переданное через
init(wrappedValue:) - ✗Зажимают в
didSet, который не срабатывает при присваивании вinit - ✗Хранят сырое значение и зажимают только при чтении свойства
- →Как
@Clampedможет выдатьprojectedValue, доступное через$? - →Почему
Valueдолжен бытьComparable, чтобы зажим скомпилировался?
Обёртка свойства — это struct с @propertyWrapper, которая хранит диапазон и backing-значение и зажимает его и в init, и в setter'е wrappedValue, поэтому даже начальное присваивание попадает в диапазон:
@propertyWrapper
struct Clamped<Value: Comparable> {
private var value: Value
private let range: ClosedRange<Value>
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: Value {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
struct Player {
@Clamped(0...100) var health: Int = 120 // health == 100
}
Зажим в init обязателен: наблюдатель didSet при инициализирующем присваивании не срабатывает, поэтому логика ограничения живёт в самой обёртке. Тип Value должен быть Comparable, иначе min/max не скомпилируются.