Swift中的switch语句允许重复的case值。这个功能还是bug?

时间:2014-11-27 02:27:42

标签: swift

swift switch语句(在Xcode 6.1中测试)允许重复切换值。请参阅下面的代码,编译和运行没有错误。显然,第一个匹配值是执行的情况。后续案例将被忽略。这是一个错误或功能吗?如果是一个功能,它有什么用?

class SwitchTest{

enum E {
  case one, two, three
  }

func test() {
  switchStmt(E.one)  // outputs: "one, two"
  switchStmt(E.two)  // outputs: "one, two"
  switchStmt(E.three) //outputs: "three, two"
}

func switchStmt(e : E)
{
  switch (e){
  case .one, .two:
    println("one, two")
  case .three, .two:
    println("three, two")
  case .one:
    println("one")
  case .two:
    println("two")
  }
}
}

3 个答案:

答案 0 :(得分:5)

如果文档说它做了一件事但它确实做了另一件事,那只是一个错误。文档在这个问题上保持沉默的任何事情在技术上只是实施者和用户之间的分歧。

然而,在这种情况下,documentation

  

然后根据成功匹配的 第一个 模式执行适当的代码块。

原因这样的事情可能与以下事实有关:与C不同,您不仅限于简单匹配。您可以在case节中提供单个值,单个值列表,范围,元组,绑定,where等附加条款,以及强制default案例(如果您没有&#39} ; t已经捕获了该类型的所有可能值。

从这个意义上讲,这是非常符合逻辑的。它只是按顺序将检查值与每个case节进行比较并执行第一个匹配的过程,无论它是否与下面的匹配都匹配。

就实用性而言,如果您想在顶部指定特定案例,并在下面指定更一般的案例,那么顺序性将会派上用场,例如使用代码:

switch num {
    case 2, 3, 5, 7, 11, 13, 17, 19:
        println("prime, 1 <= x <= 20");
    case 1...20: // don't need 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20
        println("non-prime, 1 <= x <= 20");
    default:
        println("x < 1 or x > 20");
}

通过顺序检查性质和特定于一般情况的流程,您可以简化后面的情况。

答案 1 :(得分:1)

这是一个功能 - 而不是一个bug。通过不太简单的案例可以明确它的用处。

从官方文档中考虑这个例子:

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    println("(0, 0) is at the origin")
case (_, 0):
    println("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    println("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    println("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    println("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}

如果somePoint的值为(0,0),则考虑所有案例都为true。如果元组具体为(Int, Int),则最后一种情况:case (-2...2, -2...2):可能会以逗号分隔列表完全写出(25种组合),更类似于您的示例。我们应该希望不允许我们case (0, 0):的特定情况,我们应该吗?

如果我们仅以我们习惯使用标准C风格switch语句的方式定义我们的案例,那么它没有多大意义......但是,给出了多个值在一个案例中,也不是C式switch陈述。

您的问题中的示例是Swift switch语句的一个很好的功能的一个不好的例子。


应该注意的是,如果我们要在这里对案例进行重新排序,我们很容易就会遇到switch,其中一个案例无法执行。如果我们构建这种switch语句(例如,如果我们在默认值之前移动case (0, 0):会发生什么),那么生成警告可能会很好。

但是,请考虑以下情况不会产生警告:

for i in 2...1 {
    println(i)
}

但应注意,这会崩溃:fatal error: Can't form Range with end < start

关键是,Xcode绝对不会抓住所有内容,因此我不确定为什么我们会选择switch语句。像你的问题中的例子这样的简单案例似乎很容易,但是当我们考虑Swift switch语句的复杂性时,我不确定我是否需要花费大量时间来分析我的{{1像这样的语句。

答案 2 :(得分:0)

这绝对应该是语法错误! 这将是无数复制/粘贴错误的来源。