Мені знайомі switch
заяви у Swift, але цікаво, як замінити цей фрагмент коду на switch
:
if someVar < 0 {
// do something
} else if someVar == 0 {
// do something else
} else if someVar > 0 {
// etc
}
Мені знайомі switch
заяви у Swift, але цікаво, як замінити цей фрагмент коду на switch
:
if someVar < 0 {
// do something
} else if someVar == 0 {
// do something else
} else if someVar > 0 {
// etc
}
Відповіді:
Ось один підхід. Якщо припустити someVar
, що це те Int
чи інше Comparable
, ви можете необов'язково призначити операнда новій змінній. Це дозволяє вам охоплювати його, однак ви хочете використовувати where
ключове слово:
var someVar = 3
switch someVar {
case let x where x < 0:
print("x is \(x)")
case let x where x == 0:
print("x is \(x)")
case let x where x > 0:
print("x is \(x)")
default:
print("this is impossible")
}
Це можна трохи спростити:
switch someVar {
case _ where someVar < 0:
print("someVar is \(someVar)")
case 0:
print("someVar is 0")
case _ where someVar > 0:
print("someVar is \(someVar)")
default:
print("this is impossible")
}
Ви також можете where
повністю уникнути ключового слова повністю з відповідності діапазону:
switch someVar {
case Int.min..<0:
print("someVar is \(someVar)")
case 0:
print("someVar is 0")
default:
print("someVar is \(someVar)")
}
default: fatalError()
виявити можливі логічні помилки на ранньому етапі.
assertionFailure
здається більш безпечним варіантом, особливо під час роботи в команді.
За допомогою Swift 5 ви можете вибрати один із наведених нижче перемикачів, щоб замінити свою операцію if.
PartialRangeFrom
іPartialRangeUpTo
let value = 1
switch value {
case 1...:
print("greater than zero")
case 0:
print("zero")
case ..<0:
print("less than zero")
default:
fatalError()
}
ClosedRange
іRange
let value = 1
switch value {
case 1 ... Int.max:
print("greater than zero")
case Int.min ..< 0:
print("less than zero")
case 0:
print("zero")
default:
fatalError()
}
let value = 1
switch value {
case let val where val > 0:
print("\(val) is greater than zero")
case let val where val == 0:
print("\(val) is zero")
case let val where val < 0:
print("\(val) is less than zero")
default:
fatalError()
}
_
let value = 1
switch value {
case _ where value > 0:
print("greater than zero")
case _ where value == 0:
print("zero")
case _ where value < 0:
print("less than zero")
default:
fatalError()
}
RangeExpression
протоколу~=(_:_:)
let value = 1
switch true {
case 1... ~= value:
print("greater than zero")
case ..<0 ~= value:
print("less than zero")
default:
print("zero")
}
Equatable
протоколу~=(_:_:)
let value = 1
switch true {
case value > 0:
print("greater than zero")
case value < 0:
print("less than zero")
case 0 ~= value:
print("zero")
default:
fatalError()
}
PartialRangeFrom
, PartialRangeUpTo
і RangeExpression
scontains(_:)
методlet value = 1
switch true {
case (1...).contains(value):
print("greater than zero")
case (..<0).contains(value):
print("less than zero")
default:
print("zero")
}
0.1
видає фатальну помилку, оскільки 1...
охоплює лише числа від 1. Отже, це рішення працює лише якщо value
є, Int
але це небезпечно, оскільки якщо тип змінної зміни функціональність перерветься без помилок компілятора.
switch
Заява, під капотом, використовує ~=
оператор. Отже це:
let x = 2
switch x {
case 1: print(1)
case 2: print(2)
case 3..<5: print(3..<5)
default: break
}
Десугари до цього:
if 1 ~= x { print(1) }
else if 2 ~= x { print(2) }
else if 3..<5 ~= x { print(3..<5) }
else { }
Якщо ви подивитесь на стандартну посилання на бібліотеку, вона може точно сказати, що саме ~=
робити : включено відповідність діапазону та прирівняне до рівних речей. (Не входить відповідність enum-case, яка є мовною особливістю, а не функцією в lib-файлі std)
Ви побачите, що він не відповідає прямому булевому з лівого боку. Для таких порівнянь вам потрібно додати оператор.
Якщо тільки ... ви перевантажуєте ~=
оператора самостійно. (Це, як правило, не рекомендується) Однією з можливостей буде щось подібне:
func ~= <T> (lhs: T -> Bool, rhs: T) -> Bool {
return lhs(rhs)
}
Таким чином, це відповідає функції, яка повертає булевий зліва до його параметра праворуч. Ось те, що ви могли використовувати для:
func isEven(n: Int) -> Bool { return n % 2 == 0 }
switch 2 {
case isEven: print("Even!")
default: print("Odd!")
}
Для вашого випадку у вас може бути вислів, який виглядає приблизно так:
switch someVar {
case isNegative: ...
case 0: ...
case isPositive: ...
}
Але тепер ви повинні визначити нове isNegative
іisPositive
функції. Якщо ви не перевантажите ще декількох операторів ...
Ви можете перевантажувати звичайні оператори інфіксованих файлів, щоб бути викривленими префіксами або операторами постфікса. Ось приклад:
postfix operator < {}
postfix func < <T : Comparable>(lhs: T)(_ rhs: T) -> Bool {
return lhs < rhs
}
Це діятиме так:
let isGreaterThanFive = 5<
isGreaterThanFive(6) // true
isGreaterThanFive(5) // false
Поєднайте це з попередньою функцією, і ваш вимикач може виглядати так:
switch someVar {
case 0< : print("Bigger than 0")
case 0 : print("0")
default : print("Less than 0")
}
Тепер ви, мабуть, не повинні використовувати подібні речі на практиці: це трохи хитро. Вам (напевно) краще дотримуватися where
заяви. Це сказало, схема заяви заяви
switch x {
case negative:
case 0:
case positive:
}
або
switch x {
case lessThan(someNumber):
case someNumber:
case greaterThan(someNumber):
}
Здається, досить поширеним, щоб його варто було б розглянути.
Оскільки хтось уже опублікував case let x where x < 0:
тут, це альтернатива тому, де someVar
є Int
.
switch someVar{
case Int.min...0: // do something
case 0: // do something
default: // do something
}
І ось альтернатива, де someVar
є Double
:
case -(Double.infinity)...0: // do something
// etc
Так виглядає з діапазонами
switch average {
case 0..<40: //greater or equal than 0 and less than 40
return "T"
case 40..<55: //greater or equal than 40 and less than 55
return "D"
case 55..<70: //greater or equal than 55 and less than 70
return "P"
case 70..<80: //greater or equal than 70 and less than 80
return "A"
case 80..<90: //greater or equal than 80 and less than 90
return "E"
case 90...100: //greater or equal than 90 and less or equal than 100
return "O"
default:
return "Z"
}
<0
Вираз не працює (більше?) , Так що я в кінцевому підсумку з цим:
Swift 3.0:
switch someVar {
case 0:
// it's zero
case 0 ..< .greatestFiniteMagnitude:
// it's greater than zero
default:
// it's less than zero
}
X_MAX
замінено на .greatestFiniteMagnitude
, тобто Double.greatestFiniteMagnitude
, CGFloat.greatestFiniteMagnitude
і т. Д. Так зазвичай це можна зробити, case 0..< .greatestFiniteMagnitude
оскільки тип someVar
уже відомий
var timeLeft = 100
switch timeLeft {case 0...<=7200: print("ok") default:print("nothing") }
Чому <=
оператор не розпізнається? Якщо я напишу його без рівних, це працює. Спасибі
case 0...7200:
Оператор <=
є оператором порівняння. У комутаторі ви можете використовувати лише операторів діапазону (див. Документи)
someVar
був Int
і мені довелося виконати Double(
деякий вар) `, щоб він працював ...
Радий, що Swift 4 вирішує проблему:
Як вирішення у 3 році я зробив:
switch translation.x {
case 0..<200:
print(translation.x, slideLimit)
case -200..<0:
print(translation.x, slideLimit)
default:
break
}
Працює, але не ідеально