Rust使用闭包 (closure) 来创建匿名函数:

    其中闭包借用了它作用域中的let绑定num。如果要让闭包获得所有权,
    可以使用move关键字:

    1. let mut num = 5;
    2. {
    3. let mut add_num = move |x: i32| num += x;
    4. add_num(5);
    5. }
    6. assert_eq!(5, num);

    Rust 还支持高阶函数 (high order function),允许把闭包作为参数来生成新的函数:

    1. fn add_one(x: i32) -> i32 { x + 1 }
    2. fn apply<F>(f: F, y: i32) -> i32
    3. where F: Fn(i32) -> i32
    4. {
    5. f(y) * y
    6. }
    7. fn factory(x: i32) -> Box<Fn(i32) -> i32> {
    8. Box::new(move |y| x + y)
    9. }
    10. fn main() {
    11. let transform: fn(i32) -> i32 = add_one;
    12. let f0 = add_one(2i32) * 2;
    13. let f1 = apply(add_one, 2);
    14. let f2 = apply(transform, 2);
    15. println!("{}, {}, {}", f0, f1, f2);
    16. let closure = |x: i32| x + 1;
    17. let c0 = closure(2i32) * 2;
    18. let c1 = apply(closure, 2);
    19. let c2 = apply(|x| x + 1, 2);
    20. println!("{}, {}, {}", c0, c1, c2);
    21. let box_fn = factory(1i32);
    22. let b0 = box_fn(2i32) * 2;
    23. let b1 = (*box_fn)(2i32) * 2;
    24. let b2 = (&box_fn)(2i32) * 2;
    25. println!("{}, {}, {}", b0, b1, b2);
    26. let add_num = &(*box_fn);
    27. let translate: &Fn(i32) -> i32 = add_num;
    28. let z0 = add_num(2i32) * 2;
    29. let z1 = apply(add_num, 2);
    30. let z2 = apply(translate, 2);
    31. println!("{}, {}, {}", z0, z1, z2);
    32. }

    Rust通过impl关键字在structenum或者trait对象上实现方法调用语法 (method call syntax)。
    关联函数 (associated function) 的第一个参数通常为self参数,有3种变体:

    • self,允许实现者移动和修改对象,对应的闭包特性为FnOnce
    • &self,既不允许实现者移动对象也不允许修改,对应的闭包特性为Fn
    • &mut self,允许实现者修改对象但不允许移动,对应的闭包特性为FnMut

    不含self参数的关联函数称为静态方法 (static method)。

    1. struct Circle {
    2. x: f64,
    3. y: f64,
    4. radius: f64,
    5. }
    6. impl Circle {
    7. fn new(x: f64, y: f64, radius: f64) -> Circle {
    8. Circle {
    9. x: x,
    10. y: y,
    11. radius: radius,
    12. }
    13. }
    14. fn area(&self) -> f64 {
    15. std::f64::consts::PI * (self.radius * self.radius)
    16. }
    17. }
    18. fn main() {
    19. println!("{}", c.area());
    20. // use associated function and method chaining
    21. println!("{}", Circle::new(0.0, 0.0, 2.0).area());
    22. }

    为了描述类型可以实现的抽象接口 (abstract interface),
    Rust引入了特性 (trait) 来定义函数类型签名 (function type signature):

    其中函数print_area()中的泛型参数T被添加了一个名为的特性约束 (trait constraint),
    用以确保任何实现了HasArea的类型将拥有一个.area()方法。
    如果需要多个特性限定 (multiple trait bounds),可以使用+

    1. use std::fmt::Debug;
    2. fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
    3. x.clone();
    4. y.clone();
    5. println!("{:?}", y);
    6. }
    7. fn bar<T, K>(x: T, y: K)
    8. where T: Clone,
    9. K: Clone + Debug
    10. {
    11. x.clone();
    12. y.clone();
    13. println!("{:?}", y);
    14. }

    定义在特性中的方法称为默认方法 (default method),可以被该特性的实现覆盖。
    此外,特性之间也可以存在继承 (inheritance):

    1. trait Foo {
    2. fn foo(&self);
    3. // default method
    4. fn bar(&self) { println!("We called bar."); }
    5. }
    6. // inheritance
    7. trait FooBar: Foo {
    8. fn foobar(&self);
    9. }
    10. struct Baz;
    11. impl Foo for Baz {
    12. fn foo(&self) { println!("foo"); }
    13. }
    14. impl FooBar for Baz {
    15. fn foobar(&self) { println!("foobar"); }
    16. }

    如果两个不同特性的方法具有相同的名称,可以使用通用函数调用语法 (universal function call syntax):

    1. // short-hand form
    2. Trait::method(args);
    3. // expanded form
    4. <Type as Trait>::method(args);

    关于实现特性的几条限制:

    • 如果一个特性不在当前作用域内,它就不能被实现。
    • 不管是特性还是impl,都只能在当前的包装箱内起作用。
    • 带有特性约束的泛型函数使用单态 (monomorphization),
      所以它是静态派分的 (statically dispatched)。

    下面列举几个非常有用的标准库特性:

    • Drop提供了当一个值退出作用域后执行代码的功能,它只有一个drop(&mut self)方法。
    • Borrow用于创建一个数据结构时把拥有和借用的值看作等同。
    • AsRef用于在泛型中把一个值转换为引用。
    • Deref<Target=T>用于把&U类型的值自动转换为&T类型。
    • Iterator用于在集合 (collection) 和惰性值生成器 (lazy value generator) 上实现迭代器。
    • Sized用于标记运行时长度固定的类型,而不定长的切片和特性必须放在指针后面使其运行时长度已知,
      比如&[T]Box<Trait>

    泛型 (generics) 在类型理论中称作参数多态 (parametric polymorphism),
    意为对于给定参数可以有多种形式的函数或类型。先看Rust中的一个泛型例子:

    其中<T>部分表明它是一个泛型数据类型。当然,泛型参数也可以用于函数参数和结构体域:

    1. // generic functions
    2. fn make_pair<T, U>(a: T, b: U) -> (T, U) {
    3. (a, b)
    4. }
    5. let couple = make_pair("man", "female");
    6. // generic structs
    7. struct Point<T> {
    8. x: T,
    9. y: T,
    10. }
    11. let int_origin = Point { x: 0, y: 0 };
    12. let float_origin = Point { x: 0.0, y: 0.0 };

    对于多态函数,存在两种派分 (dispatch) 机制:静态派分和动态派分。
    前者类似于C++的模板,Rust会生成适用于指定类型的特殊函数,然后在被调用的位置进行替换,
    好处是允许函数被内联调用,运行比较快,但是会导致代码膨胀 (code bloat);
    后者类似于Java或Go的interface,Rust通过引入特性对象 (trait object) 来实现,
    在运行期查找虚表 (vtable) 来选择执行的方法。特性对象&Foo具有和特性Foo相同的名称,
    通过转换 (casting) 或者强制多态化 (coercing) 一个指向具体类型的指针来创建。

    1. // use generic parameters
    2. trait Graph<N, E> {
    3. fn has_edge(&self, &N, &N) -> bool;
    4. fn edges(&self, &N) -> Vec<E>;
    5. }
    6. }
    7. // use associated types
    8. trait Graph {
    9. type N;
    10. type E;
    11. fn has_edge(&self, &Self::N, &Self::N) -> bool;
    12. }
    13. fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint {
    14. }
    15. struct Node;
    16. struct Edge;
    17. struct SimpleGraph;
    18. impl Graph for SimpleGraph {
    19. type N = Node;
    20. type E = Edge;
    21. fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
    22. }
    23. fn edges(&self, n: &Node) -> Vec<Edge> {
    24. }
    25. }
    26. let graph = SimpleGraph;
    27. let object = Box::new(graph) as Box<Graph<N=Node, E=Edge>>;

    Rust中的宏 (macro) 允许我们在语法级别上进行抽象。先来看vec!宏的实现:

    1. macro_rules! vec {
    2. ( $( $x:expr ),* ) => {
    3. {
    4. let mut temp_vec = Vec::new();
    5. $(
    6. temp_vec.push($x);
    7. )*
    8. temp_vec
    9. }
    10. };
    11. }

    其中=>左边的$x:expr模式是一个匹配器 (matcher),$x是元变量 (metavariable),
    expr是片段指定符 (fragment specifier)。匹配器写在$(...)中,
    *会匹配0个或多个表达式,表达式之间的分隔符为逗号。
    =>右边的外层大括号只是用来界定整个右侧结构的,也可以使用()或者[]
    左边的外层小括号也类似。扩展中的重复与匹配器中的重复会同步进行:
    每个匹配的$x都会在宏扩展中产生一个单独的push语句。

    Rust提供了两个特性来处理并发 (concurrency):SendSync
    当一个T类型实现了Send,就表明该类型的所有权可以在进程间安全地转移;
    而实现了Sync就表明该类型在多线程并发时能够确保内存安全。

    Rust的标准库std::thread提供了并行执行代码的功能:

    其中thread::spawn()方法接受一个闭包,它将在一个新线程中执行。

    Rust尝试解决可变状态的共享问题,通过所有权系统来帮助排除数据竞争 (data race):

    1. use std::sync::{Arc, Mutex};
    2. use std::sync::mpsc;
    3. use std::thread;
    4. fn main() {
    5. let data = Arc::new(Mutex::new(0u32));
    6. // Creates a shared channel that can be sent along from many threads
    7. // where tx is the sending half (tx for transmission),
    8. // and rx is the receiving half (rx for receiving).
    9. let (tx, rx) = mpsc::channel();
    10. for i in 0..10 {
    11. let (data, tx) = (data.clone(), tx.clone());
    12. thread::spawn(move || {
    13. let mut data = data.lock().unwrap();
    14. *data += i;
    15. tx.send(*data).unwrap();
    16. });
    17. }
    18. for _ in 0..10 {
    19. println!("{}", rx.recv().unwrap());
    20. }
    21. }

    其中Arc<T>类型是一个原子引用计数指针 (atomic reference counted pointer),
    实现了Sync,可以安全地跨线程共享。Mutex<T>类型提供了互斥锁 (mutex’s lock),
    同一时间只允许一个线程能修改它的值。mpsc::channel()方法创建了一个通道 (channel),
    来发送任何实现了Send的数据。Arc<T>clone()方法用来增加引用计数,
    而当离开作用域时计数减少。