【Swift 3 && C++11】<第一部分> 概览(2): Swift控制流与C++控制流

【Swift 3 && C++11】<第一部分> 概览(2): Swift控制流与C++控制流_第1张图片
流程图

控制流, 就是程序中的控制语句, 如 if, switch, for, while 等.但是在 Swift 和 C++中控制流有一些不同.

控制流 Swift C++
条件 if, switch if, switch
循环 for-in ,while,repeat-while for, 范围 for, while, do-while

Swift 中条件表达式和循环变量的括号可以省略, 但是大括号必须要写:

let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
print(teamScore)

C++中圆括号是必须要写的, 大括号反而可以省略. 但要注意的是, 大括号括起来的众多语句, 整体表示一条复合语句, 一个; 省略了大括号, 相应的语句体只有一条语句起作用:

#include 
using namespace std;

int main() {
    
    const int individualScores[5] = {75, 43, 103, 87, 12,};
    auto teamScore = 0;
    for (auto score : individualScores) {
        if (score > 50) {
            teamScore += 3;
        }else {
            teamScore += 1;
        }
    }
    
    cout << teamScore << endl;
    
    if (teamScore > 10) // 省略了大括号
        cout << "teamScore 大于10" <<  endl; // 此时这里只能写一条语句
    else // 省略了大括号
        cout << "teamScore 不大于10" << endl; // 此时这里只能写一条语句
    
    return 0;
}

if 语句

Swift 中 if 语句的条件必须是一个布尔表达式. 像if score {....}编译器会提示出错.

而不像在** C++中 ** score 可以是表达式或变量, 会隐式的转换成布尔类型, 当然前提是这个表达式变量必须能够支持这种转换.

Swift中可以一起使用iflet 来处理值缺失的情况. 一个可选值是一个具体的值或者nil 来表示值缺失.在类型后面加一个问号来标记这个变量的值是可选的.

var optionalString: String? = "Hello"
print(optionalString == nil)

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
// 如果变量的可选值是 nil, 条件会判断为 false, 大括号中的代码会被跳过.
// 如果不是 nil, 会将值赋给 let 后面的常量, 这样在代码块中就可以使用这个值了.
if let name = optionalName { // 这里使用 var 也是可以的
    greeting = "Hello, \(name)"
}

练习: 把 optionalName 改成 nilgreeting会是什么?添加一个 else 语句,当 optionalNamenil 时给greeting赋一个不同的值。

另一种处理可选值的方法是通过使用??来提供一个默认值.如果可选值缺失的话, 可以使用默认值来代替.

let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)"

注意 C++14中添加了可选值

C++中 if,switch,whilefor 语句的控制结构内可以定义变量. 定义在控制结构中的变量只在相应的语句的内部可见,一旦语句结束,变量也就超出其作用范围了:

#include 
using namespace std;

int main() {
    
    if (auto var = 0) // 变量 var 仅在该 `if-else` 语句内部可见
        cout << var << endl;
    
    return 0;
}

练习: 在上面的小例子中, 添加一个 else 分支,在大括号中打印 var 的值, ...else {...}.

switch 语句

Swift 中switch 支持任意类型的数据以及各种比较操作 —— 不仅仅是整型数以及测试相等。

let vegetable = "red pepper"
switch vegetable { // 关于 switch 你可以探索更多, 比如调换 case 语句的位置.
    case "celery":
        print("Add some raisins and make ants on a log.")  // 运行 switch 中匹配的子句之后, 程序会退出 switch, 并不会继续向下运行, 所以不需要在每个子句结尾写 break.
    case "cucumber", "watercress":
        print("That would make a good tea sandwich.")
    case let x where x.hasSuffix("pepper"): // 注意此处的 let 中是如何使用的,它将匹配的等式的值赋给常量 x; 此处的 let当然也可以使用 var 代替
        print("Is it a spicy \(x)?")
    default:
        print("Everything tastes good in soup.")
}

练习: 删除 default 语句,看看会有什么错误?

C++中switch 语句则不同. switch 括号中的表达式将转换为整型,然后与每个case 标签的值进行匹配. 从这点上看, C++的 switch语句功能没有 Swift 的多, 还存在更多的限制 :

#include 
using namespace std;

int main() {
    
    auto ch = 'a';
    switch (ch) {
        case 'a':
            cout << "ch 为字符 a" << endl;
            break;
        case 'b':
            cout << "ch 为字符 b" << endl;
            break;
        case 10:
            cout << "ch 的值为10" << endl;
            break;
        default:
            cout << "所有的 case 标签都没有被匹配" << endl;
            break;
    }
    
    return 0;
}

switch 语句会首先对ch 求值, 注意括号中的表达式可以是一个初始化的变量声明. 表达式的值转换成整数类型,然后与每个 case标签的值比较.

如果表达式和某个 case 标签的值匹配成功,程序从该标签之后的第一条语句开始执行, 知道到达了 switch 的结尾或者是遇到一个 break 语句为止.

break语句的作用是中断当前的控制流, 通常情况下, switch 常常与 break一起使用.

case 关键字和它对应的值一起被称为case 标签. case 标签必须是整形表达式

练习: 尝试删除上面例子中的每个 break, 会发生什么?

for语句的变式

Swift 中你可以使用for-in 来遍历字典. 此时需要两个变量来表示字典的键值对. 字典是一个无序集合,所以他们的键值对以任意顺序迭代结束.

let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
print(largest)

练习: 练习: 添加另一个变量来记录最大数字的种类(kind),同时仍然记录这个最大数字的值。

C++中你可以使用范围 for 来遍历序列,当然使用传统的for 语句也可以达到同样的效果:

#include 
#include 
#include 
#include 
using namespace std;

int main() {
    
    map> interestingNumbers = {
        {"Prime", {2, 3, 5, 7, 11, 13}},
        {"Fibonacci", {1, 1, 2, 3, 5, 8}},
        {"Square", {1, 4, 9, 16, 25}},
    };
    
    // 范围 for 语句遍历序列
    for (const auto map_value : interestingNumbers) { // map_value 将是一个 pair 类型的值
        cout << map_value.first << ": "; // pair 包含两个数据成员 first 和 second, 使用点语法 . 可以得到它们
        for (const auto item : map_value.second)
            cout << item << " ,";
        cout << endl;
    }
    
    // 传统 for语句遍历序列
    // interestingNumbers.begin()将得到 map 的开头—— 它是一个迭代器(即指针), interestingNumbers.end()则得到 map 的结尾
    for (auto map_value = interestingNumbers.begin(); map_value != interestingNumbers.end(); ++map_value ) {
        cout << (*map_value).first << ": "; // 解引用这个迭代器将得到 pair 类型的值
        for (auto item = map_value->second.begin(); item != map_value->second.end(); ++item) // 而interestingNumbers 中关键字对应的值是一个 vector, 同样也可以得到它的开头和结尾
            cout << *item << " ,"; // 解引用 vector 的迭代器将得到其中的值
        cout << endl;
    }
    
    return 0;
}

map 是一个有序的不重复的关联数组, 当对map 进行遍历的时候, map_value 将是一个pair 类型的值, pair 包含两个数据成员firstsecond, 使用点语法.可以得到它们. 其中first 表示 map 中关键字,second 表示map中关键字所关联的值.

上面例子中, map_valuesecond 是一个vector, 它也是一个序列,可以再次使用范围 for 遍历其中的元素.

interestingNumbers.begin()表示调用interestingNumbers中的begin成员函数, 它将返回关联数组interestingNumbers的开头 —— 它是一个迭代器(即指针), 关联数组interestingNumbers的结尾则由end 成员函数表示.

解引用map迭代器得到的是pair类型的值,所以想要得到里面的键值对,只需要使用点语法即可. 而map_value->second 则等同于(*map_value).second .

vectormap 或者其他容器都拥有 beginend成员函数. 不过解引用vector的迭代器*item将得到其中的值.

联系: 怎样修改代码才能将打印的结果变为这样:

{ 
   { Fibonacci, { 1 ,1 ,2 ,3 ,5 ,8 ,} },
   { Prime, { 2 ,3 ,5 ,7 ,11 ,13 , } },
   { Square, { 1 ,4 ,9 ,16 ,25 , } },
}

提示:请手动控制 cout 的输出格式

while、do-while 语句的变式

Swift中可以使用while, repeat-while 来重复运行一段代码知道不满足条件为止. 循环的条件也可以在结尾, 这样可以保证能够至少循环一次.

var n = 2
while n < 100 {
    n = n * 2
}
print(n)

var m = 2
repeat {
    m = m * 2
} while m < 100
print(m)

你也可以在循环中使用..<来表示一个范围.

var total = 0
for i in 0..<4 {
    total += i
}
print(total)

使用..<创建的范围包含下界,但不包含上界, 使用...将包含上界也包含下界 —— 类似数学中的区间[0, 4), [0, 4].

C++中则可以使用while, do-while 做到同样的目的, 但没有什么快捷的方式创建一个范围. 需要注意的是, 由于 C++中的大括号可以省略, 只能使用一条单独的语句作为循环体; do-while语句需要在最后写一个分号;表示语句结束:

#include 
using namespace std;

int main() {
    
    auto n = 2;
    while (n < 100) {
        n = n * 2;
    } // C++中一对大括号 { } 本身就表示一个复合语句, 一个块. 因此就不必在后面加上分号, 当然加上分号也不影响.
    cout << n << endl;
    
    auto m = 2;
    do
        m = m * 2; // 此处只能用一条单独的语句作为循环体
    while (m < 100); // C++中分号 ; 才表示一个语句, 所以此处需要加上分号
    cout << m << endl;
}

练习: 分别粘贴下面的代码在 Swift 中运行, 将会得到什么错误提示?

var index: Int
for index = 0; index < 3; ++index {
    print("index is \(index)")
}
var index = 0
do {
    index += 2
} while index < 100

你可能感兴趣的:(【Swift 3 && C++11】<第一部分> 概览(2): Swift控制流与C++控制流)