Как позволить функции Rust распространять состояние? - PullRequest
0 голосов
/ 25 декабря 2018

Мне нужно написать функцию Rust, которая может изменять состояние, определенное в более высокой функции, и распространять его от одного вызова функции к другому в итераторе (см. Псевдокод ниже).

В плохом C,Я бы сделал это с помощью общего указателя.Конечно, я понимаю, почему я не должен этого делать, и почему я не могу сделать это в Rust.

Обходной путь, который я нашел, заключается в добавлении дополнительного параметра функции и дополнительного возвращаемого аргумента:

fn f(inputs ..., s) {
    let mut s = s;
    // computations that rely on the value of s
    // ...
    outputs ..., s
}

fn main() {
    let mut s;
    for ... {
        let (outputs ..., x) = f(inputs ..., s);
        s = x;
    }
}

Это кажется немного тяжелым с точки зрения стиля программирования, и я надеюсь, что есть более легкая конструкция (возможно, более монадическая), я представляю себе использование замыканий.Как я должен писать, мне не очевидно.

1 Ответ

0 голосов
/ 25 декабря 2018

Ответ лежит в ссылках.

Общий указатель в C содержит предостережения относительно того, где и когда это можно сделать, а когда - нет.В Rust есть средство проверки заимствования, чтобы убедиться, что вы не делаете ничего глупого / небезопасного с указателями, чтобы предотвратить большую часть проблем, которые люди укушают в C.

Например, рассмотрите небольшое изменение вашего кода(сделано так, что компилируется).Его можно переписать следующим образом:

fn do_with(s: &mut u8, item: u8) {
    *s = *s + item;
}
fn main() {
    let mut s: u8 = 0;
    (1..10).for_each(|item| do_with(&mut s, item));
    println!("{}", s)
}

Этот синтаксис вы узнаете из C, но он намного безопаснее, чем C, поскольку средство проверки заимствования гарантирует, что в вашем коде только одна изменяемая ссылка на любой данный моментвремя.В результате код считается нормальным на каждом шаге и компилируется.

Вы также можете сделать это так, как вы это сделали, эффективно растоптав значение из вызова в вызов.Однако это приводит к менее читаемому коду и еще одному уровню косвенности.Пример ниже:

fn do_with(s: u8, item: u8) -> u8 {
    s + item
}
fn main() {
    let mut s: u8 = 0;
    (1..10).for_each(|item| s = do_with(s, item));
    println!("{}", s)
}

В C опасность указателей в основном заключается в их обслуживании и обслуживании.Поскольку Rust проверяет и применяет это для вас (и это - положительно - не позволяет вам стрелять себе в ногу, когда вы используете futures), что делает это в значительной степени не проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...