写给前端看的Rust教程(7)语言篇[上]

2,071 阅读4分钟

原文:24 days from node.js to Rust

前言

所有的语言都有一个入门标准,当达到入门标准后想要继续深入达到精通,唯有通过不断的练习

Python的入门标准比较低,因此颇为流行;JavaScript的入门难度源于异步的存在所以稍微高一些,而类型化语言更难一些,因为需要考虑额外的上下文因素。

rust的学习曲线就像是过山车,每当你觉得自己搞明白了,又会下坠到仿佛一无所知的窘境。截止到目前为止,读者还达不到入门的地步,本文将会继续来填补一些空白

语言差异

编程风格

rust的编程风格和JavaScript有些许的不同。在rust中函数、变量、模块的命名方式是下划线式的,如time_in_millis;结构体则是驼峰式的,如CpuModel;常量则是大写的下划线方式,如GLOBAL_TIMEOUT

括号的可选性

下面的写法是比较常见的

if (x > y) { /* */ }

while (x > y) { /* */ }

不过下面的方式在rust中才是首选,上面的写法linter会给出警告

if x > y { /* */ }

while x > y { /* */ }

表达式返回值

几乎所有完整的代码段都有返回值,如4 * 2返回8if true { 1 } else { 0 }返回1,这就意味着你可以将表达式给变量赋值或者作为函数的返回值,如:

fn main() {
    let apples = 6;
    let message = if apples > 10 {
        "Lots of apples"
    } else if apples > 4 {
        "A few apples"
    } else {
        "Not many apples at all"
    };

    println!("{}", message) // prints "A few apples"
}

注意上面的三个字符串后面都没有分号,你可以尝试下加了之后的结果

unit type

rust没有JavaScript中的nullundefined,不过rust中依然有“无”这个概念,我们尝试在代码if {} else if {} else {}中添加分号看看效果:

let message = if apples > 10 {
    "Lots of apples";  // ⬅ Notice the rogue semi-colon
} else if apples > 4 {
    "A few apples"
} else {
    "Not many apples at all"
};

rust不会进行编译,会给出一个“if and else have incompatible types.”的提示,完整的输出如下:

error[E0308]: `if` and `else` have incompatible types
  --> crates/day-7/syntax/src/main.rs:13:12
   |
11 |        let message = if apples > 10 {
   |   ___________________-
12 |  |         "Lots of apples";
   |  |         -----------------
   |  |         |               |
   |  |         |               help: consider removing this semicolon
   |  |         expected because of this
13 |  |     } else if apples > 4 {
   |  |____________^
14 | ||         "A few apples"
15 | ||     } else {
16 | ||         "Not many apples at all"
17 | ||     };
   | ||     ^
   | ||_____|
   | |______`if` and `else` have incompatible types
   |        expected `()`, found `&str`

输出的信息中会提示你“expected (), found &str.”,而且还会提示你移除分号,不过提示里的()是什么意思呢?()被称为是单位类型(unit type),本质上意味着“无”,一个表达式如果是分号结尾,那么就会返回一个“无”,也叫unit type。如果我们只在if {}部分增加了分号,则这部分的返回结果是“无”,编译器希望每个条件分支返回相同的类型,所以当我们删掉分号之后,各个条件分支的返回结果类型就是相同的了。

当你在报错信息中看到(),就意味着你应该在某处添加或删除分号

函数隐式返回

函数的最后一个执行代码会作为返回值,而不必添加return声明:

fn add_numbers(left: i64, right: i64) -> i64 {
    left + right  // ⬅ 注意不加分号
}

和下面的代码是等价的:

fn add_numbers(left: i64, right: i64) -> i64 {
    return left + right
}

数组

rust支持数组,关于数组我们没有讲太多,因为相关文章已经很多了,感兴趣的话可以看 Rust Book: Ch 4.3Rust by Example: Ch 2.3

rust数组相比于JavaScript数组的不足之处在于,长度必须固定且初始化的时候每个位置都要有初始值,如下面的代码就有问题:

let mut numbers = [1, 2, 3, 4, 5];
numbers.push(7);
println!("{:?}", numbers);

如果你希望得到得到类似JavaScript中的那种数组功能,你需要的是 Vec 或 VecDequeVec可以在尾部增减新内容,VecDeque则是首尾都可以

数组和迭代器在本系列文章中会专门讲,你需要知道的是,有一种简单的宏给一种Vec相似的能力:

let mut numbers = vec![1, 2, 3, 4, 5];  // ⬅ Notice the vec! macro
numbers.push(7);
println!("{:?}", numbers);

总结

The Rust Book 对于rust学习者来说非常重要,如果你到目前为止还没读过,那么赶紧去读,不然会遇到很多的麻烦;如果你已经度过,则不妨再读一遍。每当你遇到障碍时,都不妨重新读一读,每次都会有新的发现

在下一篇文章中,我们将会领略rust中的基础类型,还会展开对结构体的学习

更多