Я знаком с 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
«ы contains(_:)
метод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
}
Desugars к этому:
if 1 ~= x { print(1) }
else if 2 ~= x { print(2) }
else if 3..<5 ~= x { print(3..<5) }
else { }
Если вы посмотрите на ссылку на стандартную библиотеку, она может сказать вам, что ~=
делать перегружено версией: включается соответствие по диапазону и уравнивание для уравниваемых вещей. (Не включено сопоставление с перечислением, которое является языковой функцией, а не функцией из библиотеки std)
Вы увидите, что он не соответствует прямому логическому значению на левой стороне. Для таких сравнений вам нужно добавить оператор where.
Если только вы ~=
сами не перегружаете оператора. (Как правило, это не рекомендуется) Одна из возможностей будет выглядеть примерно так:
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 может выглядеть так:
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
был an, Int
и я должен был сделать Double(
someVar) `, чтобы это сработало ...
Рад, что Swift 4 решает проблему:
В качестве обходного пути в 3 я сделал:
switch translation.x {
case 0..<200:
print(translation.x, slideLimit)
case -200..<0:
print(translation.x, slideLimit)
default:
break
}
Работает но не идеально