读Rust By Example(8)

函数

fn 关键字声明函数,参数要指明类型,并且若有返回值则使用 -> 标明。

函数最后的表达式将作为返回值。或者在函数内使用 return 语句来提前返回值, 甚至在循环或 if 内部使用。

// 和 C/C++ 不一样,Rust 的函数定义位置是没有限制的
fn main() {  
    // 我们在这里使用函数,并在后面的其他位置定义它
    fizzbuzz_to(100);
}

// 函数返回一个布尔(boolean)值
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {  
    // 极端情况,提前返回(Corner case, early return)
    if rhs == 0 {
        return false;
    }

    // 这是一个表达式,这里可以不用 `return` 关键字
    lhs % rhs == 0
}

// 函数不返回值,而实际上是返回一个单元类型 `()`
fn fizzbuzz(n: u32) -> () {  
    if is_divisible_by(n, 15) {
        println!("fizzbuzz");
    } else if is_divisible_by(n, 3) {
        println!("fizz");
    } else if is_divisible_by(n, 5) {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}

// 当函数返回 `()` 时,可以从标记中删除返回类型
fn fizzbuzz_to(n: u32) {  
    for n in 1..n + 1 {
        fizzbuzz(n);
    }
}

方法

方法是附在对象上函数。这些方法通过关键字 self 来对象里面的数据和其他方法。方法使用一个 impl 代码块来定义。

struct Point {  
    x: f64,
    y: f64,
}

// 实现的代码块,所有的 `Point` 方法都在这里给出
impl Point {  
    // 这是一个静态方法(static method)
    // 静态方法不需要通过实例来调用
    // 这类方法一般用作构造器(constructor)
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    // 另外一个静态方法,带有两个参数:
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {  
    p1: Point,
    p2: Point,
}

impl Rectangle {  
    // 这是实例方法(instance method)
    // `&slef` 是 `self: &Self` 的语法糖(sugar),其中 `Self` 是所调用对象
    // 的类型。在这个例子中 `Self` = `Rectangle`
    fn area(&self) -> f64 {
        // `self` 通过点运算符来访问结构体字段
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        // `abs` 是一个 `f64` 类型的方法,返回调用者的绝对值
        ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }

    // 这个方法要求调用者对象是可变的
    // `&mut self` 为 `self: &mut Self` 的语法糖
    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p2.x += x;

        self.p1.y += y;
        self.p2.y += y;
    }
}

// `Pair` 含有的资源:两个堆分配的整型
struct Pair(Box<i32>, Box<i32>);

impl Pair {  
    // 这个方法“消费”调用者对象的资源
    // `self` 为 `self: Self` 的语法糖
    fn destroy(self) {
        // 解构 `self`
        let Pair(first, second) = self;

        println!("Destroying Pair({}, {})", first, second);

        // `first` 和 `second` 离开作用域后释放
    }
}

fn main() {  
    let rectangle = Rectangle {
        // 静态方法使用双重冒号来调用
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };

    // 实例方法通过点运算符来调用
    // 注意第一个参数 `&self` 是隐式传递的,比如:
    // `rectangle.perimeter()` === `perimeter(&rectangle)`
    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());

    let mut square = Rectangle {
        p1: Point::origin(),
        p2: Point::new(1.0, 1.0),
    };

    // 报错! `rectangle` 是不可变的,但这方法需要一个可变对象
    //rectangle.translate(1.0, 0.0);
    // 试一试 ^ 将此行注释去掉

    // 正常运行!可变对象可以调用可变方法
    square.translate(1.0, 1.0);

    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();

    // 报错!前面的 `destroy` 调用“消费了” `pair`
    //pair.destroy();
    // 试一试 ^ 将此行注释去掉
}