Swift编程语言学习4.3—— 控制语句

控制传递语句(Control Transfer Statements)

控制转移语句改变你代码的运行顺序,通过它你能够实现代码的跳转。Swift有四种控制转移语句。

continue

break

fallthrough

return

我们将会在以下讨论continue、break和fallthrough语句。return语句将会在函数章节讨论。

Continue

continue语句告诉一个循环体立马停止本次循环迭代,又一次開始下次循环迭代。就好像在说“本次循环迭代我已经运行完了”,可是并不会离开整个循环体。

注意:

在一个for条件递增(for-condition-increment)循环体中,在调用continue语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,只不过循环体中的运行代码会被跳过。

以下的样例把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句:

let puzzleInput = "great minds thinkalike"
var puzzleOutput = ""
for character in puzzleInput {
   switch character {
   case "a", "e", "i", "o","u", " ":
       continue
   default:
       puzzleOutput += character
    }
}
println(puzzleOutput)
   // 输出 "grtmndsthnklk"

在上面的代码中,仅仅要匹配到元音字母或者空格字符,就调用continue语句,使本次循环迭代结束,从新開始下次循环迭代。这样的行为使switch匹配到元音字母和空格字符时不做处理,而不是让每个匹配到的字符都被打印。

Break

break语句会立马结束整个控制流的运行。当你想要更早的结束一个switch代码块或者一个循环体时,你都能够使用break语句。

循环语句中的 break

当在一个循环体中使用break时,会立马中断该循环体的运行,然后跳转到表示循环体结束的大括号(})后的第一行代码。不会再有本次循环迭代的代码被运行,也不会再有下次的循环迭代产生。

Switch 语句中的 break

当在一个switch代码块中使用break时,会马上中断该switch代码块的运行,而且跳转到表示switch代码块结束的大括号(})后的第一行代码。

这样的特性能够被用来匹配或者忽略一个或多个分支。由于 Swift 的switch须要包括全部的分支并且不同意有为空的分支,有时为了使你的意图更明显,须要特意匹配或者忽略某个分支。那么当你想忽略某个分支时,能够在该分支内写上break语句。当那个分支被匹配到时,分支内的break语句马上结束switch代码块。

注意:

当一个switch分支只包括凝视时,会被报编译时错误。凝视不是代码语句并且也不能让switch分支达到被忽略的效果。你总是能够使用break来忽略某个分支。

以下的样例通过switch来推断一个Character值是否代表以下四种语言之中的一个。为了简洁,多个值被包括在了同一个分支情况中。

let numberSymbol: Character = "三"  // 中文简体里的数字 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "?","一", "?":
   possibleIntegerValue = 1
case "2", "?","二", "?":
   possibleIntegerValue = 2
case "3", "?","三", "?":
   possibleIntegerValue = 3
case "4", "?","四", "?":
   possibleIntegerValue = 4
default:
   break
}
if let integerValue = possibleIntegerValue{
   println("The integer value of \(numberSymbol) is\(integerValue).")
} else {
   println("An integer value could not be found for\(numberSymbol).")
}
// 输出 "The integervalue of 三 is 3."

这个样例检查numberSymbol是否是拉丁,阿拉伯,中文或者泰语中的1到4之中的一个。假设被匹配到,该switch分支语句给Int?类型变量possibleIntegerValue设置一个整数值。

当switch代码块运行完后,接下来的代码通过使用可选绑定来推断possibleIntegerValue是否以前被设置过值。由于是可选类型的缘故,possibleIntegerValue有一个隐式的初始值nil,所以只当possibleIntegerValue曾被switch代码块的前四个分支中的某个设置过一个值时,可选的绑定将会被判定为成功。

在上面的样例中,想要把Character全部的的可能性都枚举出来是不现实的,所以使用default分支来包括全部上面没有匹配到字符的情况。因为这个default分支不须要运行不论什么动作,所以它仅仅写了一条break语句。一旦落入到default分支中后,break语句就完毕了该分支的全部代码操作,代码继续向下,開始运行if let语句。

贯穿(Fallthrough)

Swift 中的switch不会从上一个 case 分支落入到下一个 case分支中。相反,仅仅要第一个匹配到的 case 分支完毕了它须要运行的语句,整个switch代码块完毕了它的运行。相比之下,C 语言要求你显示的插入break语句到每一个switch分支的末尾来阻止自己主动落入到下一个 case 分支中。Swift 的这样的避免默认落入到下一个分支中的特性意味着它的switch 功能要比C 语言的更加清晰和可预測,能够避免无意识地运行多个 case 分支从而引发的错误。

假设你确实须要 C 风格的贯穿(fallthrough)的特性,你能够在每一个须要该特性的 case 分支中使用fallthroughkeyword。以下的样例使用fallthrough来创建一个数字的描写叙述语句。

let integerToDescribe = 5
var description = "The number\(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
   description += " a prime number, and also"
   fallthrough
default:
   description += " an integer."
}
println(description)
// 输出 "The number 5is a prime number, and also an integer."

这个样例定义了一个String类型的变量description而且给它设置了一个初始值。函数使用switch逻辑来推断integerToDescribe变量的值。当integerToDescribe的值属于列表中的质数之中的一个时,该函数加入一段文字在description后,来表明这个是数字是一个质数。然后它使用fallthroughkeyword来“贯穿”到default分支中。default分支加入一段额外的文字在description的最后,至此switch代码块运行完了。

假设integerToDescribe的值不属于列表中的不论什么质数,那么它不会匹配到第一个switch分支。而这里没有其它特别的分支情况,所以integerToDescribe匹配到包括全部的default分支中。

当switch代码块运行完后,使用println函数打印该数字的描写叙述。在这个样例中,数字5被准确的识别为了一个质数。

注意:

fallthroughkeyword不会检查它下一个将会落入运行的case 中的匹配条件。fallthrough简单地使代码运行继续连接到下一个 case 中的运行代码,这和 C 语言标准中的switch语句特性是一样的。

带标签的语句(Labeled Statements)

在 Swift 中,你能够在循环体和switch代码块中嵌套循环体和switch代码块来创造复杂的控制流结构。然而,循环体和switch代码块两者都能够使用break语句来提前结束整个方法体。因此,显示地指明break语句想要终止的是哪个循环体或者switch代码块,会非常实用。类似地,假设你有很多嵌套的循环体,显示指明continue语句想要影响哪一个循环体也会非常实用。

为了实现这个目的,你能够使用标签来标记一个循环体或者switch代码块,当使用break或者continue时,带上这个标签,能够控制该标签代表对象的中断或者运行。

产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,而且该标签后面还需带着一个冒号。以下是一个while循环体的语法,相同的规则适用于全部的循环体和switch代码块。

`label name`: while `condition` {
   `statements`
}

以下的样例是在一个带有标签的while循环体中调用break和continue语句,该循环体是前面章节中蛇和梯子的改编版本号。这次,游戏添加了一条额外的规则:

为了获胜,你必须刚好落在第 25 个方块中。

假设某次掷骰子使你的移动超出第 25 个方块,你必须又一次掷骰子,直到你掷出的骰子数刚好使你能落在第 25 个方块中。

游戏的棋盘和之前一样:

值finalSquare、board、square和diceRoll的初始化也和之前一样:

let finalSquare = 25
var board = Int[](count: finalSquare + 1,repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09]= +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22]= -02; board[24] = -08
var square = 0
var diceRoll = 0

这个版本号的游戏使用while循环体和switch方法块来实现游戏的逻辑。while循环体有一个标签名gameLoop,来表明它是蛇与梯子的主循环。

该while循环体的条件推断语句是while square !=finalSquare,这表明你必须刚好落在方格25中。

gameLoop: while square != finalSquare {
   if ++diceRoll == 7 { diceRoll = 1 }
   switch square + diceRoll {
   case finalSquare:
       // 到达最后一个方块,游戏结束
       break gameLoop
   case let newSquare where newSquare > finalSquare:
       // 超出最后一个方块,再掷一次骰子
       continue gameLoop
   default:
       // 本次移动有效
       square += diceRoll
       square += board[square]
    }
}
println("Game over!")

每次循环迭代開始时掷骰子。与之前玩家掷完骰子就马上移动不同,这里使用了switch来考虑每次移动可能产生的结果,从而决定玩家本次是否可以移动。

假设骰子数刚好使玩家移动到终于的方格里,游戏结束。break gameLoop语句跳转控制去运行while循环体后的第一行代码,游戏结束。

假设骰子数将会使玩家的移动超出最后的方格,那么这样的移动是不合法的,玩家须要又一次掷骰子。continue gameLoop语句结束本次while循环的迭代,開始下一次循环迭代。

在剩余的全部情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到while循环体的条件推断语句处,再决定是否可以继续运行下次循环迭代。

注意:

假设上述的break语句没有使用gameLoop标签,那么它将会中断switch代码块而不是while循环体。使用gameLoop标签清晰的表明了break想要中断的是哪个代码块。同一时候请注意,当调用continue gameLoop去跳转到下一次循环迭代时,这里使用gameLoop标签并非严格必须的。由于在这个游戏中,仅仅有一个循环体,所以continue语句会影响到哪个循环体是没有歧义的。然而,continue语句使用gameLoop标签也是没有危害的。这样做符合标签的使用规则,同一时候參照旁边的break
gameLoop,可以使游戏的逻辑更加清晰和易于理解。

时间: 2024-11-05 12:25:10

Swift编程语言学习4.3—— 控制语句的相关文章

Swift编程语言学习2.2——基本运算符(下)

三元条件运算(Ternary Conditional Operator) 三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是问题?答案1:答案2.它简洁地表达根据问题成立与否作出二选一的操作.如果问题成立,返回答案1的结果; 如果不成立,返回答案2的结果. 使用三元条件运算简化了以下代码: if question: { answer1 } else { answer2 } 这里有个计算表格行高的例子.如果有表头,那行高应比内容高度要高出50像素; 如果没有表头,只需高出20像素. let

Swift编程语言学习1.5——类型别名、布尔值、元组

类型别名 类型别名(type aliases)就是给现有类型定义另一个名字.你可以使用typealias关键字来定义类型别名. 当你想要给现有类型起一个更有意义的名字时,类型别名非常有用.假设你正在处理特定长度的外部资源的数据: typealias AudioSample = UInt16 定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名: var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 现在是 0 本例中,A

Swift编程语言学习1.6——可选值

可选值 使用可选(optionals)来处理值可能缺失的情况.可选表示: 有值,等于 x   或者没有值 注意: C 和 Objective-C 中并没有可选这个概念.最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回nil,nil表示"缺少一个合法的对象".然而,这只对对象起作用--对于结构体,基本的 C 类型或者枚举类型不起作用.对于这些类型,Objective-C 方法一般会返回一个特殊值(比如NSNotFound)来暗示值缺失.这种方法假设方法的

Swift编程语言学习1.7——断言

断言 可选可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况.然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能并不需要继续执行.这时,你可以在你的代码中触发一个断言(assertion)来结束代码运行并通过调试来找到值缺失的原因. 使用断言进行调试 断言会在运行时判断一个逻辑条件是否为true.从字面意思来说,断言"断言"一个条件是否为真.你可以使用断言来保证在运行其他代码之前,某些重要的条件已经被满足.如果条件判断为true,代码运行会继续进行:如果条件

Swift编程语言学习——常量与变量

常量和变量把一个名字(比如maximumNumberOfLoginAttempts或者welcomeMessage)和一个指定类型的值(比如数字10或者字符串"Hello")关联起来.常量的值一旦设定就不能改变,而变量的值可以随意更改. 声明常量和变量 常量和变量必须在使用前声明,用let来声明常量,用var来声明变量.下面的例子展示了如何用常量和变量来记录用户尝试登录的次数: let maximumNumberOfLoginAttempts = 10 var currentLogin

Swift编程语言学习2.1——基本运算符(上)

运算符是检查,改变,合并值的特殊符号或短语.例如,加号+将两个数相加(如let i = 1 + 2).复杂些的运行算例如逻辑与运算符&&(如if enteredDoorCode && passedRetinaScan),又或让 i 值加1的便捷运算符自增运算符++i等. Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误.如,赋值符(=)不返回值,以防止把想要判断相等运算符(==)的地方写成赋值符导致的错误.数值运算符(+,-,*,/,%等)会检

Swift编程语言学习——数值型字面量、数值类型转换

数值型字面量 整数字面量可以被写作: 一个十进制数,没有前缀 一个二进制数,前缀是0b 一个八进制数,前缀是0o 一个十六进制数,前缀是0x 下面的所有整数字面量的十进制值都是17: let decimalInteger = 17 let binaryInteger = 0b10001 // 二进制的17 let octalInteger = 0o21 // 八进制的17 let hexadecimalInteger = 0x11 // 十六进制的17 浮点字面量可以是十进制(没有前缀)或者是十

Swift 编程语言学习——Swift简介

有的时候,觉得看英文文档有些费时,看中文文档怕翻译不准,有些地方确实不需要抠字眼,当有些地方如果翻译不精准会产生歧义,所以用这样对照的方式,顺便学习一下Swift. Swift is a new programming language for iOS and OS X apps that builds on the best of C and Objective-C, without the constraints of C compatibility. Swift adopts safe p

Swift编程语言学习——类型安全和类型推测

Swift 是一种类型安全(type safe )的语言.类型安全的语言可以让你清楚地知道代码要处理的值的类型.如果你的代码需要一个String,你绝对不可能不小心传进去一个Int. 由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误.这可以让你在开发的时候尽早发现并修复错误. 当你要处理不同类型的值时,类型检查可以帮你避免错误.然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型.如果你没有显式指定类型,Swift