Rust изменяемый необязательный OutputPin - PullRequest
0 голосов
/ 13 октября 2019

Я новичок в ржавчине и застрял в теме владения. Я думал, что получил это, но не могу сделать Option<OutputPin> в моей функции пригодной для использования. Подскажите, пожалуйста, как это должно быть?

struct Chip {
    wake_pin: Option<OutputPin>
}

impl Chip {
    pub fn new(wake_pin: Option<Pin>) -> Chip {
        Chip {
            wake_pin: wake_pin.map(|pin| pin.into_output())
        }
    }

    pub fn awake(&self) {
        // Fails
        if let Some(pin) = self.wake_pin {
            pin.set_low();
        } 
    }
}

fn main() {
    let wake_pin = Gpio::new().expect("Can not init gpio")
        .get(255).expect("Could not attach to wake pin");

    let chip = Chip::new(Some(wake_pin));
}

Я использую rppal crate, и компилятор не работает в области if let Some. Я пытался позаимствовать wake_pin, получить опцию в качестве ссылки и некоторые другие вещи, но до сих пор не полностью понял правило владения.

Спасибо

1 Ответ

3 голосов
/ 13 октября 2019

Полагаю, я продублировал ваши настройки. Если что-то не так, пожалуйста, отредактируйте свой вопрос с соответствующими деталями.

src / main.rs:

use rppal::gpio::{Gpio, OutputPin, Pin};

struct Chip {
    wake_pin: Option<OutputPin>,
}

impl Chip {
    pub fn new(wake_pin: Option<Pin>) -> Chip {
        Chip {
            wake_pin: wake_pin.map(|pin| pin.into_output()),
        }
    }

    pub fn awake(&self) {
        // Fails
        if let Some(pin) = self.wake_pin {
            pin.set_low();
        }
    }
}

fn main() {
    let wake_pin = Gpio::new()
        .expect("Can not init gpio")
        .get(255)
        .expect("Could not attach to wake pin");

    let chip = Chip::new(Some(wake_pin));
}

Cargo.toml:

[package]
name = "tmp"
version = "0.0.1"
edition = "2018"

[dependencies]
rppal = "0.11.3"

Пытаясь скомпилировать это (с cargo check или аналогичным), мы получаем предупреждение и две ошибки.

warning: unused variable: `chip`
  --> src/main.rs:28:9
   |
28 |     let chip = Chip::new(Some(wake_pin));
   |         ^^^^ help: consider prefixing with an underscore: `_chip`
   |
   = note: `#[warn(unused_variables)]` on by default

error[E0507]: cannot move out of `self.wake_pin.0` which is behind a shared reference
  --> src/main.rs:16:28
   |
16 |         if let Some(pin) = self.wake_pin {
   |                     ---    ^^^^^^^^^^^^^ help: consider borrowing here: `&self.wake_pin`
   |                     |
   |                     data moved here
   |                     move occurs because `pin` has type `rppal::gpio::pin::OutputPin`, which does not implement the `Copy` trait

error[E0596]: cannot borrow `pin` as mutable, as it is not declared as mutable
  --> src/main.rs:17:13
   |
16 |         if let Some(pin) = self.wake_pin {
   |                     --- help: consider changing this to be mutable: `mut pin`
17 |             pin.set_low();
   |             ^^^ cannot borrow as mutable

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0507, E0596.
For more information about an error, try `rustc --explain E0507`.
error: Could not compile `tmp`.

To learn more, run the command again with --verbose.

Поскольку вы, вероятно, собираетесь использовать chip позже, мыможно отключить предупреждение, временно переименовав его в _chip.

let _chip = Chip::new(Some(wake_pin));

Первая ошибка говорит нам, что мы не можем вытащить пин-код из self, поскольку мытолько заимствование self. Было бы довольно грубо аннулировать данные за собой, если мы только заимствуем их. Тем не менее, компилятор говорит нам решение. help: consider borrowing here: `&self.wake_pin`

В конечном итоге это не совсем верно, но это правильное направление.

if let Some(pin) = &self.wake_pin {
    pin.set_low();
}

Теперь вместо pin с типом OutputPin (собственное значение), этоимеет тип &OutputPin (заимствованное значение).

Мы все еще получаем вторую ошибку, хотя (с немного другой формулировкой). Дело в том, что pin.set_low() требует, чтобы pin был изменяемой ссылкой. Прямо сейчас мы берем self как неизменную ссылку (pub fn awake(&self)). Если мы собираемся изменить self или любое из его полей, мы должны принять его изменчиво. Это также означает, что мы должны быть уверены, что pin заимствовано.

pub fn awake(&mut self) {
    if let Some(pin) = &mut self.wake_pin {
        pin.set_low();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...