控制流(Control Flow)
https://doc.rust-lang.org/book/ch06-02-match.html
所有权(Ownership)
https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
异常处理(Error Handling)
https://doc.rust-lang.org/book/ch09-00-error-handling.html
字符串(String)
https://doc.rust-lang.org/book/ch08-02-strings.html
生命周期(Lifetimes)
https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html
面向对象特性(Object Oriented Programming Features)
https://doc.rust-lang.org/book/ch17-00-oop.html
其他语言特性比较
以下是阅读本书过程中的一些零星的语言特性比较的感悟。
临时变量命名
在 js 代码中,经常会遇到需要在作用域中对参数做多轮临时处理的情况,难免会遭遇起名困难:
function formatList(rawList) {
const processedList = filterEmpty(rawList);
const groupList = groupListByType(processedList, 'some-type');
const neededList = filterNeeded(groupList);
// ...
return [...];
}
其中,processedList
groupList
neededList
等等只是一串中间处理过程,本身没有太多实际意义。rust 中,变量具有 隐藏(shadowing) 特性,支持在同一个作用域内多次使用同一个变量名,即新变量的声明可以覆盖掉旧的同名变量:
fn main() {
let x = 5; // x 并非 mut 变量,相当于 js 的 const
let x = x + 1;
let x = String::new("hello, world"); // 甚至可以变成其他类型
}
看起来非常实用,很多时候直接可以单个名字一把梭,再也不用担心怎么为起不一样的名字了。也许,这可能得益于其变量默认 immutable 的设计理念。
语句结束的分号
在 rust 里,很可能需要关注函数体中的语句(Statement)与表达式(expression)。语句指那些执行操作、但不返回值的指令,而表达式是指会进行计算、并最终产生一个值作为结果的指令。但,如果我们给表达式结尾添加分号“;”, 其就会变成语句,而不产生任何值:
fn add1(v: i32): i32 {
v + 1
}
fn add2(v: i32): i32 {
v + 2;
}
以上两个函数,前者会将最后一句 v + 1
表达式的值作为函数返回值,而后者会发生编译错误,因为它具有分号,变成了语句,不能满足函数签名。
这也是一点 rust 和 js 有很大差异的点,从语法规范上就杜绝了语句结束“加不加分号”的争论。这个省掉一个 return 语句的操作,很难说它好还是不好,只能说更加精细化了。
鸭子类型
对于 TS 来说,一个很显著的特性就是我们可以定义两个不同名的类型,只要满足对方的类型约束,就可以当成另外一个类型使用,即:有一个东西,它长得像鸭子,叫的像鸭子,会游泳,那它就可以认为是鸭子。
interface Duck {
name: string;
swim () {};
}
function letDuckSwim(duck: Duck) {
duck.swim();
}
interface Something {
name: string;
swim () {};
fly () {};
}
const sm: Something = {
name: 'some strange thing',
swim () {
console.log('swimming now!');
}
fly () {
console.log('flying now!');
}
}
letDuckSwim(sm);
// output: swimming now!;
但是在 rust 中,所定义的每个结构体(可以暂时理解为 ts 中 interface)都拥有自己的类型,即便在结构体中的字段拥有完全相同的类型:
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
示例中,black
和 origin
是不同的类型,它们是不同元组结构体的实例,不能混用。这与 TS 的鸭子类型特性完全相反。
总结
以一个略懂一些 C++ 的前端开发人员的视角囫囵吞枣的看完,只感觉 Rust 好难。它逼迫程序员去思考程序逻辑背后的实现原理,开发人员必须很清楚的理解堆栈结构、字符编码、引用关系、异常处理,还有所有权规则之下的一系列设计速录。从这个角度看,Rust 对大批仅凭“语感”理解程序语言并从事开发的人来说,门槛颇高。