Выбрать главу

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

enum, Option, and the RFC

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 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<i32>, Box<i32>);

impl Pair {

// This method "consumes" the resources of the caller object

// `self` desugars to `self: Self`

fn destroy(self) {

// Destructure `self`

let Pair(first, second) = self;

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

// `first` and `second` go out of scope and get freed

}

}

fn main() {

let rectangle = Rectangle {

// Static methods are called using double colons

p1: Point::origin(),

p2: Point::new(3.0, 4.0),

};

// Instance methods are called using the dot operator

// Note that the first argument `&self` is implicitly passed, i.e.

// `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`

println!("Rectangle perimeter: {}", rectangle.perimeter());

println!("Rectangle area: {}", rectangle.area());

let mut square = Rectangle {