【Rust练习】14.流程控制

练习题来自:https://practice-zh.course.rs/flow-control.html

1

rust 复制代码
// 填空
fn main() {
    let n = 5;

    if n < 0 {
        println!("{} is negative", n);
    } __ n > 0 {
        println!("{} is positive", n);
    } __ {
        println!("{} is zero", n);
    }
} 

非常简单的if-else

rust 复制代码
fn main() {
    let n = 5;

    if n < 0 {
        println!("{} is negative", n);
    } else if n > 0 {
        println!("{} is positive", n);
    } else {
        println!("{} is zero", n);
    }
} 

2 🌟🌟 if/else 可以用作表达式来进行赋值

rust 复制代码
// 修复错误
fn main() {
    let n = 5;

    let big_n =
        if n < 10 && n > -10 {
            println!(" 数字太小,先增加 10 倍再说");

            10 * n
        } else {
            println!("数字太大,我们得让它减半");

            n / 2.0 ;
        }

    println!("{} -> {}", n, big_n);
} 

能通过if表达式直接赋值也是现代语言的一个新鲜玩意了,不知道为什么C++不打个补丁支持下。

rust 复制代码
fn main() {
    let n = 5;

    let big_n = if n < 10 && n > -10 {
        println!(" 数字太小,先增加 10 倍再说");

        10 * n
    } else {
        println!("数字太大,我们得让它减半");

        n / 2
    };

    println!("{} -> {}", n, big_n);
}

3 for in 可以用于迭代一个迭代器,例如序列 a...b.

rust 复制代码
fn main() {
    for n in 1..=100 { // 修改此行,让代码工作
        if n == 100 {
            panic!("NEVER LET THIS RUN")
        }
    }
} 

始终记得Rust的range是一个左闭右开区间,想要包含右边就得加上等号就行,这里就要去掉。

rust 复制代码
fn main() {
    for n in 1..100 { // 修改此行,让代码工作
        if n == 100 {
            panic!("NEVER LET THIS RUN")
        }
    }
} 

题外话:Rust 目前还是一个比较新的语言,主流的 IDE 为 VS Code(安装 rust-analyzer 插件)和 RustRover,前者无论商用还是非商用都是不收费的,后者非商用不收费,商用收费(应该是 Jetbrains 旗下第一个这么收费的,其他 IDE 都是任何使用都得收费)。下面提到的 VS Code 都指的是加载了 rust-analyzer 插件的。

就我个人的体验来看,两者各有各的长处。

这是 VS Code 的代码:

这是 Rustrover 的代码:

可以看到 VS Code 对变量的染色更充分一点,不过 Rustrover 对这个 range 的提示就很不错,你基本不可能认为会跑到 100。由于Rust存在类型推导的机制,因此当你不清楚变量的类型时,IDE提供的类型提示就尤为重要。这点 Rustrover 不如 VS Code,尤其是对于一些特征的推导,Rustrover 只能推导出基本类型,VS Code就能推导出impl trait

另外如果你想阅读库代码时,Rustrover有个将注释文档排版的功能,非常不错:

VS Code这边可能是考虑到你用浏览器也能访问本地排版好的文档,就没有这个功能,少开一个浏览器还是省了不少事的。

我们接下来的代码都以 VS Code 为基准 IDE。

4

rust 复制代码
// 修复错误,不要新增或删除代码行
fn main() {
    let names = [String::from("liming"),String::from("hanmeimei")];
    for name in names {
        // do something with name...
    }

    println!("{:?}", names);

    let numbers = [1, 2, 3];
    // numbers中的元素实现了 Copy,因此无需转移所有权
    for n in numbers {
        // do something with name...
    }
    
    println!("{:?}", numbers);
}

string 不是基本类型,因此需要借用

rust 复制代码
fn main() {
    let names = [String::from("liming"),String::from("hanmeimei")];
    for name in &names {
        // do something with name...
    }

    println!("{:?}", names);

    let numbers = [1, 2, 3];
    // numbers中的元素实现了 Copy,因此无需转移所有权
    for n in numbers {
        // do something with name...
    }
    
    println!("{:?}", numbers);
}

5

rust 复制代码
fn main() {
    let a = [4,3,2,1];

    // 通过索引和值的方式迭代数组 `a` 
    for (i,v) in a.__ {
        println!("第{}个元素是{}",i+1,v);
    }
}

固定用法了。

rust 复制代码
fn main() {
    let a = [4,3,2,1];

    // 通过索引和值的方式迭代数组 `a` 
    for (i,v) in a.iter().enumerate() {
        println!("第{}个元素是{}",i+1,v);
    }
}

6 🌟🌟 当条件为 true 时,while 将一直循环

rust 复制代码
// 填空,让最后一行的  println! 工作 !
fn main() {
    // 一个计数值
    let mut n = 1;

    // 当条件为真时,不停的循环
    while n __ 10 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }


        __;
    }

    println!("n 的值是 {}, 循环结束",n);
}

这道题应该是拿大名鼎鼎的 Fizzbuzz 题目改的。

rust 复制代码
fn main() {
    // 一个计数值
    let mut n = 1;

    // 当条件为真时,不停的循环
    while n < 10 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }

        n += 1;
    }

    println!("n 的值是 {}, 循环结束", n);
}

我就顺便把这道题做了吧,应该是我用Rust写的第一道算法题,之前用C++写过一遍。Fizzbuzz题目如下:

给你一个整数 n ,找出从 1 到 n 各个整数的 Fizz Buzz 表示,并用字符串数组 answer(下标从 1 开始)返回结果,其中:

answer[i] == "FizzBuzz" 如果 i 同时是 3 和 5 的倍数。

answer[i] == "Fizz" 如果 i 是 3 的倍数。

answer[i] == "Buzz" 如果 i 是 5 的倍数。

answer[i] == i (以字符串形式)如果上述条件全不满足。

这里用 LeetCode 的提交格式:

rust 复制代码
impl Solution {
    pub fn fizz_buzz(n: i32) -> Vec<String> {
        let mut i = 1;

        let mut res: Vec<String> = Vec::new();

        while i <= n {
            if i % 15 == 0 {
                res.push("FizzBuzz".to_string());
            } else if i % 3 == 0 {
                res.push("Fizz".to_string());
            } else if i % 5 == 0 {
                res.push("Buzz".to_string());
            } else {
                res.push(i.to_string());
            }

            i += 1;
        }

        res
    }
}

7 🌟 使用 break 可以跳出循环

rust 复制代码
// 填空,不要修改其它代码
fn main() {
    let mut n = 0;
    for i in 0..=100 {
       if n == 66 {
           __
       }
       n += 1;
    }

    assert_eq!(n, 66);
}

答案

rust 复制代码
fn main() {
    let mut n = 0;
    for _ in 0..=100 {
       if n == 66 {
           break;
       }
       n += 1;
    }

    assert_eq!(n, 66);
}

8 🌟 continue 会结束当次循环并立即开始下一次循环

rust 复制代码
// 填空,不要修改其它代码
fn main() {
    let mut n = 0;
    for i in 0..=100 {
       if n != 66 {
           n+=1;
           __;
       }
       
       __
    }

    assert_eq!(n, 66);
}

答案

rust 复制代码
// 填空,不要修改其它代码
fn main() {
    let mut n = 0;
    for i in 0..=100 {
       if n != 66 {
           n+=1;
           continue;
       }
       
       break;
    }

    assert_eq!(n, 66);
}

9 🌟🌟 loop 一般都需要配合 break 或 continue 一起使用。

rust 复制代码
// 填空,不要修改其它代码
fn main() {
    let mut count = 0u32;

    println!("Let's count until infinity!");

    // 无限循环
    loop {
        count += 1;

        if count == 3 {
            println!("three");

            // 跳过当此循环的剩余代码
            __;
        }

        println!("{}", count);

        if count == 5 {
            println!("OK, that's enough");

            __;
        }
    }

    assert_eq!(count, 5);
}

答案

rust 复制代码
fn main() {
    let mut count = 0u32;

    println!("Let's count until infinity!");

    // 无限循环
    loop {
        count += 1;

        if count == 3 {
            println!("three");

            // 跳过当此循环的剩余代码
            continue;;
        }

        println!("{}", count);

        if count == 5 {
            println!("OK, that's enough");

            break;
        }
    }

    assert_eq!(count, 5);
}

C++是没有loop(无限循环)的,很多其他的语言也没有,原因很明显,无限循环一旦不写终止条件,很容易就成了死循环。而Rust的编译器也没有智能到检测到死循环的存在,比如这里注释掉第二个ifbreakloop直接就死循环了,编译器也是很老实地跑,没有任何报错或者警告。倒是VS Code给了一个代码不可达(unreachable)的提示。

所以我不是很建议在代码里使用loop

10 🌟🌟 loop 是一个表达式,因此我们可以配合 break 来返回一个值

rust 复制代码
fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            __;
        }
    };

    assert_eq!(result, 20);
}

很有意思的设计,C++实现类似功能估计要多写点代码------包个函数就有入栈出栈的性能损耗,直接修改又不容易让人意识到变量已经被修改了。

rust 复制代码
fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter;
        }
    };

    assert_eq!(result, 20);
}

11 🌟🌟🌟 当有多层循环时,你可以使用 continue 或 break 来控制外层的循环。要实现这一点,外部的循环必须拥有一个标签 'label, 然后在 break 或 continue 时指定该标签

rust 复制代码
// 填空
fn main() {
    let mut count = 0;
    'outer: loop {
        'inner1: loop {
            if count >= 20 {
                // 这只会跳出 inner1 循环
                break 'inner1; // 这里使用 `break` 也是一样的
            }
            count += 2;
        }

        count += 5;

        'inner2: loop {
            if count >= 30 {
                break 'outer;
            }

            continue 'outer;
        }
    }

    assert!(count == __)
}

答案

rust 复制代码
// 填空
fn main() {
    let mut count = 0;
    'outer: loop {
        'inner1: loop {
            if count >= 20 {
                // 这只会跳出 inner1 循环
                break 'inner1; // 这里使用 `break` 也是一样的
            }
            count += 2;
        }

        count += 5;

        'inner2: loop {
            if count >= 30 {
                break 'outer;
            }

            continue 'outer;
        }
    }

    assert!(count == 30)
}

对比其他语言的goto,Rust的这个弱化了一点,仅仅能对循环打label,但是这已经让人不好走查代码了。我的建议也是:不要用。几乎所有编程书在介绍语言里的goto时都不建议使用,用起来很爽,看代码很痛苦。

相关推荐
Ajiang282473530410 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
盼海15 分钟前
排序算法(五)--归并排序
数据结构·算法·排序算法
幽兰的天空15 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’5 小时前
C++ list (链表)容器
c++·链表·list
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024065 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎