首页 热点资讯 义务教育 高等教育 出国留学 考研考公
您的当前位置:首页正文

Control Flow (控制流下)

2024-12-17 来源:华拓网

Labeled Statements (带标签的语句)

In Swift, you can nest loops and conditional statements inside other loops and conditional statements to create complex control flow structures. However, loops and conditional statements can both use thebreakstatement to end their execution prematurely. Therefore, it is sometimes useful to be explicit about which loop or conditional statement you want abreakstatement to terminate. Similarly, if you have multiple nested loops, it can be useful to be explicit about which loop thecontinuestatement should affect.

在 Swift 中,你可以在循环体和条件语句中嵌套循环体和条件语句来创造复杂的控制流结构。并且,循环体和条件语句都可以使用break语句来提前结束整个代码块。因此,显式地指明break语句想要终止的是哪个循环体或者条件语句,会很有用。类似地,如果你有许多嵌套的循环体,显式指明continue语句想要影响哪一个循环体也会非常有用。

To achieve these aims, you can mark a loop statement or conditional statement with astatement label. With a conditional statement, you can use a statement label with thebreakstatement to end the execution of the labeled statement. With a loop statement, you can use a statement label with thebreakorcontinuestatement to end or continue the execution of the labeled statement.

为了实现这个目的,你可以使用标签(statement label)来标记一个循环体或者条件语句,对于一个条件语句,你可以使用break加标签的方式,来结束这个被标记的语句。对于一个循环语句,你可以使用break或者continue加标签,来结束或者继续这条被标记语句的执行。

A labeled statement is indicated by placing a label on the same line as the statement’s introducer keyword, followed by a colon. Here’s an example of this syntax for awhileloop, although the principle is the same for all loops andswitchstatements:

声明一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,作为这个语句的前导关键字(introducor keyword),并且该标签后面跟随一个冒号。下面是一个针对while循环体的标签语法,同样的规则适用于所有的循环体和条件语句。

label name:whilecondition{

    statements

}

The following example uses thebreakandcontinuestatements with a labeledwhileloop for an adapted version of theSnakes and Laddersgame that you saw earlier in this chapter. This time around, the game has an extra rule:

下面的例子是前面章节中蛇和梯子的适配版本,在此版本中,我们将使用一个带有标签的while循环体中调用break和continue语句。这次,游戏增加了一条额外的规则:

  To win, you must landexactlyon square 25.

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

If a particular dice roll would take you beyond square 25, you must roll again until you roll the exact number needed to land on square 25.

如果某次掷骰子使你的移动超出第 25 个方块,你必须重新掷骰子,直到你掷出的骰子数刚好使你能落在第 25 个方块中。

The game board is the same as before.

游戏的棋盘和之前一样:

The values offinalSquare,board,square, anddiceRollare initialized in the same way as before:

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

let finalSquare=25

var board= [Int](repeating:0,count:finalSquare+1)

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

This version of the game uses awhileloop and aswitchstatement to implement the game’s logic. Thewhileloop has a statement label calledgameLoopto indicate that it is the main game loop for the Snakes and Ladders game.

这个版本的游戏使用while循环和switch语句来实现游戏的逻辑。while循环有一个标签名gameLoop,来表明它是游戏的主循环。

Thewhileloop’s condition iswhile square != finalSquare, to reflect that you must land exactly on square 25.

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

gameLoop: while square != finalSquare {

    diceRoll+=1

    if diceRoll==7 {diceRoll=1}

    switch square+diceRoll{

     case finalSquare:

        // diceRoll will move us to the final square, so the game is over

        // 骰子数刚好使玩家移动到最终的方格里,游戏结束。

            break gameLoop

    case let newSquarewherenewSquare>finalSquare:

        // diceRoll will move us beyond the final square, so roll again

        // 骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子

            continue gameLoop

    default:

         // this is a valid move, so find out its effect

        // 合法移动,做正常的处理

            square+=diceRoll

            square+=board[square]

    }

}

print("Game over!")

The dice is rolled at the start of each loop. Rather than moving the player immediately, the loop uses aswitchstatement to consider the result of the move and to determine whether the move is allowed:

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

1. If the dice roll will move the player onto the final square, the game is over. Thebreak gameLoopstatement transfers control to the first line of code outside of thewhileloop, which ends the game.

如果骰子数刚好使玩家移动到最终的方格里,游戏结束。break gameLoop语句跳转控制去执行while循环体后的第一行代码,意味着游戏结束。

2. If the dice roll will move the playerbeyondthe final square, the move is invalid and the player needs to roll again. Thecontinue gameLoopstatement ends the currentwhileloop iteration and begins the next iteration of the loop.

如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。continue gameLoop语句结束本次while循环,开始下一次循环。

3. In all other cases, the dice roll is a valid move. The player moves forward bydiceRollsquares, and the game logic checks for any snakes and ladders. The loop then ends, and control returns to thewhilecondition to decide whether another turn is required.

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

Note

If thebreakstatement above did not use thegameLooplabel, it would break out of theswitchstatement, not thewhilestatement. Using thegameLooplabel makes it clear which control statement should be terminated.

如果上述的break语句没有使用gameLoop标签,那么它将会中断switch语句而不是while循环。使用gameLoop标签清晰的表明了break想要中断的是哪个代码块。

It is not strictly necessary to use thegameLooplabel when callingcontinue gameLoopto jump to the next iteration of the loop. There is only one loop in the game, and therefore no ambiguity as to which loop thecontinuestatement will affect. However, there is no harm in using thegameLooplabel with thecontinuestatement. Doing so is consistent with the label’s use alongside thebreakstatement and helps make the game’s logic clearer to read and understand.

同时请注意,当调用continue gameLoop去跳转到下一次循环迭代时,这里使用gameLoop标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以continue语句会影响到哪个循环体是没有歧义的。然而,continue语句使用gameLoop标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的break gameLoop,能够使游戏的逻辑更加清晰和易于理解。

Early Exit (提前退出)

Aguardstatement, like anifstatement, executes statements depending on the Boolean value of an expression. You use aguardstatement to require that a condition must be true in order for the code after theguardstatement to be executed. Unlike anifstatement, aguardstatement always has anelseclause—the code inside theelseclause is executed if the condition is not true.

像if语句一样,guard的执行取决于一个表达式的布尔值。我们可以使用guard语句来要求条件必须为真时,以执行guard语句后的代码。不同于if语句,一个guard语句总是有一个else从句,如果条件不为真则执行else从句中的代码。

func greet(person: [String:String]) {

        guard let name=person["name"] else {

              return

        }

       print("Hello\(name)!")

       guardletlocation=person["location"]else{

             print("I hope the weather is nice near you.")

            return

       }

        print("I hope the weather is nice in\(location).")

}

greet(person: ["name":"John"])

// Prints "Hello John!"

// Prints "I hope the weather is nice near you."

greet(person: ["name":"Jane","location":"Cupertino"])

// Prints "Hello Jane!"

// Prints "I hope the weather is nice in Cupertino."

If theguardstatement’s condition is met, code execution continues after theguardstatement’s closing brace. Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that theguardstatement appears in.

如果guard语句的条件被满足,则继续执行guard语句大括号后的代码。将变量或者常量的可选绑定作为guard语句的条件,都可以保护guard语句后面的代码。

If that condition is not met, the code inside theelsebranch is executed. That branch must transfer control to exit the code block in which theguardstatement appears. It can do this with a control transfer statement such asreturn,break,continue, orthrow, or it can call a function or method that doesn’t return, such asfatalError(_:file:line:).

如果条件不被满足,在else分支上的代码就会被执行。这个分支必须转移控制以退出guard语句出现的代码段。它可以用控制转移语句如return,break,continue或者throw做这件事,或者调用一个不返回的方法或函数,例如fatalError()。

Using aguardstatement for requirements improves the readability of your code, compared to doing the same check with anifstatement. It lets you write the code that’s typically executed without wrapping it in anelseblock, and it lets you keep the code that handles a violated requirement next to the requirement.

相比于可以实现同样功能的if语句,按需使用guard语句会提升我们代码的可读性。它可以使你的代码连贯的被执行而不需要将它包在else块中,它可以使你在紧邻条件判断的地方,处理违规的情况。

Checking API Availability (检测API的可用性)

Swift has built-in support for checking API availability, which ensures that you don’t accidentally use APIs that are unavailable on a given deployment target.

Swift内置支持检查 API 可用性,这可以确保我们不会在当前部署机器上,不小心地使用了不可用的API。

The compiler uses availability information in the SDK to verify that all of the APIs used in your code are available on the deployment target specified by your project. Swift reports an error at compile time if you try to use an API that isn’t available.

编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。

You use anavailability conditionin aniforguardstatement to conditionally execute a block of code, depending on whether the APIs you want to use are available at runtime. The compiler uses the information from the availability condition when it verifies that the APIs in that block of code are available.

我们在if或guard语句中使用可用性条件(availability condition)去有条件的执行一段代码,来在运行时判断调用的API是否可用。编译器使用从可用性条件语句中获取的信息去验证,在这个代码块中调用的 API 是否可用。

if #available(iOS10, macOS10.12, *) {

    // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS

} else {

    // Fall back to earlier iOS and macOS APIs

}

The availability condition above specifies that on iOS, the body of theifexecutes only on iOS 10 and later; on macOS, only on macOS 10.12 and later. The last argument,*, is required and specifies that on any other platform, the body of theifexecutes on the minimum deployment target specified by your target.

以上可用性条件指定,在iOS中,if语句的代码块仅仅在 iOS 10 及更高的系统下运行;在 macOS中,仅在 macOS 10.12 及更高才会运行。最后一个参数,*,是必须的,用于指定在所有其它平台中,如果版本号高于你的设备指定的最低版本,if语句的代码块将会运行。

if #available(platform nameversion,..., *) {

    statements to execute if the APIs are available

} else {

    fallback statements to execute if the APIs are unavailable

}

显示全文