Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Як вхідні параметри

Хоча Rust обирає, як захоплювати змінні на льоту, здебільшого без анотації типу, ця неоднозначність не допускається під час написання функцій. Коли замикання передається як вхідний параметр, його повний тип має бути анотований за допомогою одного з кількох traits, і вони визначаються тим, що замикання робить із захопленим значенням. У порядку зменшення обмежувальності вони такі:

  • Fn: замикання використовує захоплене значення через посилання (&T)
  • FnMut: замикання використовує захоплене значення через змінне посилання (&mut T)
  • FnOnce: замикання використовує захоплене значення за значенням (T)

Для кожної змінної окремо компілятор захоплюватиме змінні найменш обмежувальним способом, наскільки це можливо.

Наприклад, розгляньте параметр, анотований як FnOnce. Це визначає, що замикання може захоплювати через &T, &mut T або T, але компілятор зрештою обере залежно від того, як захоплені змінні використовуються в замиканні.

Це тому, що якщо можливе переміщення, то будь-який тип запозичення також має бути можливим. Зауважте, що зворотне не є правдою. Якщо параметр анотовано як Fn, тоді захоплення змінних через &mut T або T не дозволяється. Однак &T дозволяється.

У наведеному нижче прикладі спробуйте поміняти місцями використання Fn, FnMut і FnOnce, щоб побачити, що станеться:

// A function which takes a closure as an argument and calls it.
// <F> denotes that F is a "Generic type parameter"
fn apply<F>(f: F) where
    // The closure takes no input and returns nothing.
    F: FnOnce() {
    // ^ TODO: Try changing this to `Fn` or `FnMut`.

    f();
}

// A function which takes a closure and returns an `i32`.
fn apply_to_3<F>(f: F) -> i32 where
    // The closure takes an `i32` and returns an `i32`.
    F: Fn(i32) -> i32 {

    f(3)
}

fn main() {
    use std::mem;

    let greeting = "hello";
    // A non-copy type.
    // `to_owned` creates owned data from borrowed one
    let mut farewell = "goodbye".to_owned();

    // Capture 2 variables: `greeting` by reference and
    // `farewell` by value.
    let diary = || {
        // `greeting` is by reference: requires `Fn`.
        println!("I said {}.", greeting);

        // Mutation forces `farewell` to be captured by
        // mutable reference. Now requires `FnMut`.
        farewell.push_str("!!!");
        println!("Then I screamed {}.", farewell);
        println!("Now I can sleep. zzzzz");

        // Manually calling drop forces `farewell` to
        // be captured by value. Now requires `FnOnce`.
        mem::drop(farewell);
    };

    // Call the function which applies the closure.
    apply(diary);

    // `double` satisfies `apply_to_3`'s trait bound
    let double = |x| 2 * x;

    println!("3 doubled: {}", apply_to_3(double));
}

Див. також:

std::mem::drop, Fn, FnMut, Generics, where і FnOnce