Я знаком с 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иPartialRangeUpTolet value = 1
switch value {
case 1...:
print("greater than zero")
case 0:
print("zero")
case ..<0:
print("less than zero")
default:
fatalError()
}
ClosedRangeиRangelet 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
}
Работает но не идеально