小于或大于Swift switch语句


145

我熟悉switchSwift中的语句,但想知道如何用来替换这段代码switch

if someVar < 0 {
    // do something
} else if someVar == 0 {
    // do something else
} else if someVar > 0 {
    // etc
}

尽管这是一个有趣的问题,但我认为使用switch的代码比if语句的可读性差得多。仅仅因为您可以,并不意味着您应该。
Rog

Answers:


241

这是一种方法。假设someVarInt或其他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)")
}

9
我建议default: fatalError()及早发现可能的逻辑错误。
Martin R

1
谢谢!这些示例非常有帮助,它们可以解决我的问题!(其他例子也不错,但您的例子对我最有帮助)
Pieter

1
@MartinR assertionFailure似乎是一个更安全的选择,尤其是在团队合作中。
Michael Voline

119

使用Swift 5,您可以选择以下开关之一来替换if语句。


#1将开关与PartialRangeFromPartialRangeUpTo

let value = 1

switch value {
case 1...:
    print("greater than zero")
case 0:
    print("zero")
case ..<0:
    print("less than zero")
default:
    fatalError()
}

#2将开关与ClosedRangeRange

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()
}

#3在where子句中使用switch

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()
}

#4将switch与where子句一起使用并分配给 _

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()
}

#5与RangeExpression协议的~=(_:_:)运算符一起使用switch

let value = 1

switch true {
case 1... ~= value:
    print("greater than zero")
case ..<0 ~= value:
    print("less than zero")
default:
    print("zero")
}

#6与Equatable协议的~=(_:_:)运算符一起使用switch

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()
}

#7使用交换机PartialRangeFromPartialRangeUpToRangeExpressioncontains(_:)方法

let value = 1

switch true {
case (1...).contains(value):
    print("greater than zero")
case (..<0).contains(value):
    print("less than zero")
default:
    print("zero")
}

1
为什么在#2中需要默认大小写?似乎胡言乱语,如果范围是从Int.min到Int.max,还剩下什么?
μολὼν.λαβέ

哇,不错的选项列表。很高兴知道有很多方法可以做到这一点。
克里斯托弗·皮克斯雷

2
概述不错,但有缺陷,因为未说明0到1之间的数字。0.1引发致命错误,因为1...仅涵盖1以后的数字。因此,此解决方案仅在value为时才有效,Int但这很危险,因为如果变量类型更改,功能中断就不会出现任何编译器错误。
曼努埃尔

1
您的解决方案不适用于Double类型。情况1 ...:打印(“大于零”)不大于0,则是大于或等于1
弗拉德

20

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 {  }

如果您看一下标准库参考,它可以准确地告诉您什么~=是重载:包括范围匹配和等于等值的东西。(不包括枚举大小写匹配,这是一种语言功能,而不是标准库中的函数)

您会发现它与左侧的直线布尔值不匹配。对于这种比较,您需要添加一个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: ...
}

但是现在您必须定义new isNegativeisPositive函数。除非您重载更多运算符...

您可以将普通的infix运算符重载为咖喱前缀或postfix运算符。这是一个例子:

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语句模式

switch x {
case negative:
case 0:
case positive:
}

要么

switch x {
case lessThan(someNumber):
case someNumber:
case greaterThan(someNumber):
}

似乎很普遍,值得考虑。


1
您对问题的回答在哪里?我找不到
亲爱的

1
情况3 .. <5:print(3 .. <5)-从字面上看是第一段。这个答案被低估了。节省了我很多代码。
卡里姆

14

您可以:

switch true {
case someVar < 0:
    print("less than zero")
case someVar == 0:
    print("eq 0")
default:
    print("otherwise")
}

6

既然已经有人贴出case let x where x < 0:这里是哪里的替代someVar是一个Int

switch someVar{
case Int.min...0: // do something
case 0: // do something
default: // do something
}

这是哪里的替代品 someVarDouble

case -(Double.infinity)...0: // do something
// etc

6

这是范围的样子

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"
}

3

<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
    }

1
在swift 3.0中,X_MAX已被替换为.greatestFiniteMagnitude,即Double.greatestFiniteMagnitudeCGFloat.greatestFiniteMagnitude等等。因此通常,您可以这样做,case 0..< .greatestFiniteMagnitude因为的类型someVar是已知的
Guig,2016年

@Dorian Roy var timeLeft = 100 switch timeLeft {case 0...<=7200: print("ok") default:print("nothing") }为什么 <=无法识别操作员?如果我在没有平等的情况下编写它,它将起作用。谢谢
bibscy

@bibscy您要使用封闭范围运算符:case 0...7200:该运算符<=是比较运算符。在开关中,您只能使用范围运算符(请参阅文档)
Dorian Roy

太好了 我遇到了'Range <Double>'类型的错误表达模式,无法匹配'Int'类型的值,因为我someVar是an Int,因此我必须做Double(someVar)`才能使它工作...
蜂蜜

2

很高兴Swift 4解决了这个问题:

作为3中的解决方法,我做到了:

switch translation.x  {
case  0..<200:
    print(translation.x, slideLimit)
case  -200..<0:
    print(translation.x, slideLimit)
default:
    break
}

可行但不理想

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.