Rust by Example — страница 17 из 66

match optional {

// If `optional` destructures, evaluate the block.

Some(i) => {

if i > 9 {

println!("Greater than 9, quit!");

optional = None;

} else {

println!("`i` is `{:?}`. Try again.", i);

optional = Some(i + 1);

}

// ^ Requires 3 indentations!

},

// Quit the loop when the destructure fails:

_ => { break; }

// ^ Why should this be required? There must be a better way!

}

}

}

Using while let makes this sequence much nicer:

fn main() {

// Make `optional` of type `Option`

let mut optional = Some(0);

// This reads: "while `let` destructures `optional` into

// `Some(i)`, evaluate the block (`{}`). Else `break`.

while let Some(i) = optional {

if i > 9 {

println!("Greater than 9, quit!");

optional = None;

} else {

println!("`i` is `{:?}`. Try again.", i);

optional = Some(i + 1);

}

// ^ Less rightward drift and doesn't require

// explicitly handling the failing case.

}

// ^ `if let` had additional optional `else`/`else if`

// clauses. `while let` does not have these.

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

See also:

enum, Option, and the RFC

Functions

Functions are declared using the fn keyword. Its arguments are type annotated, just like variables, and, if the function returns a value, the return type must be specified after an arrow ->.

The final expression in the function will be used as return value. Alternatively, the return statement can be used to return a value earlier from within the function, even from inside loops or if statements.

Let's rewrite FizzBuzz using functions!

// Unlike C/C++, there's no restriction on the order of function definitions

fn main() {

// We can use this function here, and define it somewhere later

fizzbuzz_to(100);

}

// Function that returns a boolean value

fn is_divisible_by(lhs: u32, rhs: u32) -> bool {

// Corner case, early return

if rhs == 0 {

return false;

}

// This is an expression, the `return` keyword is not necessary here

lhs % rhs == 0

}

// Functions that "don't" return a value, actually return the unit type `()`

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);

}

}

// When a function returns `()`, the return type can be omitted from the

// signature

fn fizzbuzz_to(n: u32) {

for n in 1..n + 1 {

fizzbuzz(n);

}

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Methods

Methods are functions attached to objects. These methods have access to the data of the object and its other methods via the self keyword. Methods are defined under an impl block.

struct Point {

x: f64,

y: f64,

}

// Implementation block, all `Point` methods go in here

impl Point {

// This is a static method

// Static methods don't need to be called by an instance

// These methods are generally used as constructors

fn origin() -> Point {

Point { x: 0.0, y: 0.0 }

}

// Another static method, taking two arguments:

fn new(x: f64, y: f64) -> Point {

Point { x: x, y: y }

}

}

struct Rectangle {

p1: Point,

p2: Point,

}

impl Rectangle {

// This is an instance method

// `&self` is sugar for `self: &Self`, where `Self` is the type of the

// caller object. In this case `Self` = `Rectangle`

fn area(&self) -> f64 {

// `self` gives access to the struct fields via the dot operator

let Point { x: x1, y: y1 } = self.p1;

let Point { x: x2, y: y2 } = self.p2;

// `abs` is a `f64` method that returns the absolute value of the

// caller

((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())

}

// This method requires the caller object to be mutable

// `&mut self` desugars to `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` owns resources: two heap allocated integers

struct Pair(Box