在Swift中的Switch语句

46

我正在学习Swift的语法,想知道为什么下面的代码不能像我预期的那样工作:

for i in 1...100{

    switch (i){
    case 1:
        Int(i%3) == 0
        println("Fizz")
    case 2:
        Int(i%5) == 0
        println("Buzz")
    default:
        println("\(i)")
    }  
}

我希望在每次数字能被3整除时(3、6、9、12等)打印Fizz,并在它能被5整除时打印Buzz。缺少哪个重要的部分?

注意:我已使用以下代码解决了这个问题:

for ( var i = 0; i < 101; i++){

    if (Int(i%3) == 0){
        println("Fizz")
    }   else if (Int(i%5) == 0){
        println("Buzz")
    }   else {
        println("\(i)")
    }   
}

我想知道如何使用Switch解决这个问题。谢谢。


6
你读过Swift指南中的开关语句了吗? - Bryan Chen
3
这个情况下,使用If-Else比Switch更好。 - Mohit
不,Bryan,我还没有阅读参考指南,谢谢你提供链接。 - Evgeniy Kleban
2
你的代码中有一个逻辑错误:对于任何既能被3整除又能被5整除的数字,你只打印了“Fizz”,而没有打印“Fizz Buzz”。 - Atomix
我不熟悉游戏规则,但我会尝试理解语法 :) - Evgeniy Kleban
8个回答

111
通常FizzBuzz游戏的规则是将3的倍数替换为“Fizz”,将5的倍数替换为“Buzz”,同时是3和5的倍数则替换为“FizzBuzz”。 可以通过对元组(i % 3, i % 5)进行switch语句来实现此功能。 请注意,_表示“任何值”:
for i in 1 ... 100 {
    switch (i % 3, i % 5) {
    case (0, 0):
        print("FizzBuzz")
    case (0, _):
        print("Fizz")
    case (_, 0):
        print("Buzz")
    default:
        print(i)
    }
}

4
对我来说,这看起来像是对本应被问到的问题的正确回答 :) - Matt Gibson
这有点难以理解,但我认为这是正确的答案,谢谢Martin。 - Evgeniy Kleban
6
好的,翻译如下:优美的答案 :) 就是利用一种语言的特定优点来解决问题。 - Dx_
1
@Dx 同意。我喜欢你可以一次性切换多个值的方式。Python 甚至没有 switch 语句。 - Peter Schorn

24

Swift中的switch语句支持值绑定。
这允许您将与某个条件(通过where子句评估)匹配的值分配给临时变量(此处为xy):

for i in 1...100 {
    switch (i){
    case let x where x%3 == 0:
        println("Fizz")
    case let y where y%5 == 0:
        println("Buzz")
    default:
        println("\(i)")
    }
}

在 case 语句块中,您也可以使用分配的临时变量。

更新:
Matt Gibson 在评论中指出,如果您不打算在 case 语句块中使用它,则可以省略对临时变量的分配。
因此,上述代码的更简洁版本如下:

for i in 1...100 {
    switch (i){
    case _ where i%3 == 0:
        println("Fizz")
    case _ where i%5 == 0:
        println("Buzz")
    default:
        println("\(i)")
    }
}

顺便提一下:你的两个代码示例略有不同(第一个使用0-100的范围作为输入,而第二个操作1-100)。我的示例是基于你的第一个代码片段。


2
你不需要使用"let x"、"let y",因为你并没有真正使用这些值,你可以这样做,例如:case _ where i%3 == 0: - Matt Gibson
谢谢 - 我不知道那个。我更新了我的答案。 - Thomas Zoechling
非常感谢weichsel为我澄清这个问题。 - Evgeniy Kleban

20

这是一个更通用的回答,适用于那些只想知道如何在Swift中使用switch语句的人。

通用用法

switch someValue {
case valueOne:
    // executable code
case valueTwo:
    // executable code
default:
    // executable code
}

例子

let someValue = "horse"

switch someValue {
case "horse":
    print("eats grass")
case "wolf":
    print("eats meat")
default:
    print("no match")
}

注意:

  • 不需要使用break语句,这是默认行为。Swift switch语句不会“穿透”执行下一个case。如果要让它们执行下一个case中的代码,则必须显式使用fallthrough关键字。
  • 每个case必须包含可执行代码。如果要忽略某个case,可以添加一个单独的break语句。
  • case必须是全面的,也就是说,它们必须涵盖所有可能的值。如果包含足够的case语句不可行,则可以在最后加入default语句以捕获任何其他值。

Swift switch语句非常灵活。以下部分介绍了一些其他使用方法。

匹配多个值

如果使用逗号将值分隔开,则可以在一个case中匹配多个值。这被称为复合案例

let someValue = "e"

switch someValue {
case "a", "b", "c":
    // executable code
case "d", "e":
    // executable code
default:
    // executable code
}

你也可以匹配整个区间

let someValue = 4

switch someValue {
case 0..<10:
    // executable code
case 10...100:
    // executable code
default:
    // executable code
}

你甚至可以使用tuples。这个例子是从文档中改编而来的。

let aPoint = (1, 1)

switch aPoint {
case (0, 0):
    // only catches an exact match for first and second
case (_, 0):
    // any first, exact second
case (-2...2, -2...2):
    // range for first and second
default:
    // catches anything else
}

值绑定

有时您可能想要从 switch 值创建一个临时常量或变量。您可以在 case 语句之后立即执行此操作。在使用值绑定的任何地方,它都将与任何值匹配。这类似于在上面的元组示例中使用 _。以下两个示例修改自文档

let anotherPoint = (2, 0)

switch anotherPoint {
case (let x, 0):
    // can use x here
case (0, let y):
    // can use y here
case let (x, y):
    // can use x or y here, matches anything so no "default" case is necessary
}

您可以使用where关键字进一步精确匹配。

let yetAnotherPoint = (1, -1)

switch yetAnotherPoint {
case let (x, y) where x == y:
    // executable code
case let (x, y) where x == -y:
    // executable code
case let (x, y):
    // executable code
}

深入学习

  • 此答案旨在提供快速参考。请阅读完整的文档以获取更多信息。这并不难理解。

4
这就是如何实现它。
var i = 0

switch i  {

case i where i % 5 == 0 && i % 3 == 0: print(" Fizz Buzz")
case i where i % 3 == 0 : print("Fizz")
case i where i % 5 == 0 : print("Buzz")
default: print(i)

}

1
行业标准的 switch 行为可能会导致类似于 "Go to Fail" 的错误。基本上,当阅读代码时,代码并不总是像看起来那样执行,这会导致代码审计人员忽略关键的 bug。为了应对这个问题,苹果决定在 Swift 中使 switch 语句与行业标准不同。具体而言:
  • 每个 case 结尾都有自动 break。不可能同时执行多个 case 语句。
  • 如果理论上可能会漏掉某个 case,则代码根本无法编译。在 Swift 中,无论提供什么值,其中一个 case 语句将始终执行。如果提供了枚举类型,则必须处理每个枚举值。如果向现有枚举中添加新值,则在添加新的 case 语句之前,代码将无法编译。如果提供 32 位整数,则必须处理 32 位整数的每种可能值。

Abhi,很有趣,你的意思是我不能像在for-in中那样使用枚举来处理“switch”语句吗?它只能处理“小”的数量级事件? - Evgeniy Kleban
1
请注意,您可以使用 fallthrough 关键字避免自动中断,并且对于 32 位整数,使用 default 处理未特定处理的每种情况是可以的。 - Matt Gibson
@MattGibson 但那是自动的贯穿,不会在下一个 case 上进行测试 - 所以在 OP 的情况下无用。 - mmmmmm
1
@Mark 我的评论(将近三年前!哇!)只是针对这个答案中的“不可能执行多个case语句”,而不是针对OP。 - Matt Gibson

0

以下是我在解决这类问题时使用 switch 语句的两种方法。

1>> 使用 where 关键字

func printNumberType(number : Int){
    
    switch number {
    case number where number % 3 == 0 && number % 5 == 0 :
        print("foo bar")
    case number where number % 3 == 0 :
        print("foo")
    case number where number % 5 == 0 :
        print("bar")
    default :
        print("Number is not divisible by 3 and 5")
    }
}

2>> 使用值的组合

func printNumberByMultipleValues(number : Int){
    
    let combination = (number % 3,number % 5)
    
    switch combination {
    case (0,0):
        print("foo bar")
    case (0,_) :
        print("foo")
    case (_,0) :
        print("bar")
    default :
        print("Number is not divisible by 3 and 5")
    }
}

这里是多值类型的更贴近的例子。

var printNumberByMultipleValues : (Int)->() = { number in
    
    let combination = (number % 3,number % 5)
    
    switch combination {
    case (0,0):
        print("foo bar")
    case (0,_) :
        print("foo")
    case (_,0) :
        print("bar")
    default :
        print("Number is not divisible by 3 and 5")
    }
}

-1

玩弄这个东西时,我想出了两种读起来有点不同的解决方案。个人更喜欢使用switch语句,并在我的索引数字上使用.isMultiple(of: 3)。

选项1 | Switch

for i in 1...100 {
    switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) {
    case (true, true):
        print("\(i) | FizzBuzz")
    case (true, false):
        print("\(i) | Fizz")
    case (false, true):
        print("\(i) | Buzz")
    default:
        print(i)
    }
}

选项 2 | If语句

for i in 1...100 {
    if i.isMultiple(of: 3) && i.isMultiple(of: 5) {
        print("\(i) | FizzBuzz")
    } else if i.isMultiple(of: 3) {
        print("\(i) | Fizz")
    } else if i.isMultiple(of: 5) {
        print("\(i) | Buzz")
    } else {
        print(i)
    }
}

-1
使用这段代码。你的逻辑是错误的。你的 Switch 语句没有找到接受 1 和 2 的情况。
class TEST1{
func print() -> Void{
    var i = 0
    for i in 1...100{
        if Int(i%3) == 0 {
            println("Fizz")
        }
        else if Int(i%5) == 0{
            println("Buzz")
        }
        else {
            println("\(i)")
        }   
    }
}
}
var x = TEST1()
x.print()

你读完了我的整篇文章吗?请再仔细阅读, 我已经使用for-in语句和“if-else”完成此操作。 - Evgeniy Kleban
4
Bhaskar,我问了如何使用switch语句解决这个任务。请仔细看看人们所要求的内容。你的答案没有提供任何解决方案或提示,如何解决我的问题。谢谢。 - Evgeniy Kleban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接