質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

受付中

RustでクレートのStructを自作の複数のインスタンスで共有して使用したい。 cannot move out of dereference of ~~~

_filu
_filu

総合スコア0

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0回答

0評価

0クリップ

226閲覧

投稿2022/07/20 07:07

前提

現在、Rust + ESP32でI2Cに接続したPWMボードと9軸センサーを制御するプログラムを作成している。

同じI2Cバスに2つの制御対象を接続するため、I2Cインスタンスは共有したいと考えたため、

I2Cはesp_idf_halクレートを使用してインスタンスを生成し、
そのインスタンスを保持する自作のI2CDriverクラスを作成し、
PWMコントローラークラスと9軸コントローラークラスでそのI2CDriverクラスのインスタンスを共有して保持するように作成していた。

今回の問題が発生した経緯

次にPCA9685チップが搭載されているPWMボードの制御をおこないたいと思い、
PWM-Pca9685クレートを使用し、
PWMコントローラークラス内で保持しているI2Cインスタンスを使用してPca9685構造体をnew関数でインスタンス化しようとした。

しかし、new関数の引数にI2Cインスタンスを渡そうとすると、

cannot move out of dereference of `RefMut<'_, &mut I2CDriver<I2C, SDA, SCL>>` move occurs because value has type `esp_idf_hal::i2c::Master<I2C, SDA, SCL>`, which does not implement the `Copy` trait

とエラーが表示されてしまう。

I2CインスタンスはI2CDriver<~~~>構造体が保持しており、
I2CDriver<~~~>構造体はRc<RefCell<I2CDriver<~~~>>>の形でPWMコントローラーが保持している。

Rc<RefCell<I2CDriver<~~~>>>の形でI2Cインスタンスを保持することで、PWMコントローラーでも9軸コントローラーでもI2Cインスタンスを保持することができることは確認している。

このRc<RefCell<I2CDriver<~~~>>>は、Rc::clone()してさらにborrow_mut()すれば、I2CDriverをCopyしなくても参照として保持することができ、インスタンスを実体として関数に渡せるようになるとの認識だったため、エラーがどうしても解決できずにいる。

質問内容

Q1. クレートの関数の引数にインスタンスを渡す時、コピーしなくてもよい方法があるかどうか。
Q2. もしなければ、複数箇所で使用したいインスタンスの所有権を奪われるクレートに対して、どのような回避策があるのか

をご教授お願い致します。

ソースコード

pwm_controller.rs

Rust

use esp_idf_hal::{ gpio::{InputPin, OutputPin}, i2c::{self as esp_i2c_mod}, }; use std::{cell::RefCell, rc::Rc}; use i2c_driver::i2c::I2CDriver; use i2c_driver::i2c::I2CMasterTrait; use anyhow; use pwm_pca9685::{Address, Channel, Pca9685}; pub struct PwmController<'i2c_driver, I2C, SDA, SCL> where I2C: esp_i2c_mod::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin, { pub i2c_driver: Rc<RefCell<&'i2c_driver mut I2CDriver<I2C, SDA, SCL>>>, pub slave_id: u8, } impl<I2C, SDA, SCL> PwmController<'_, I2C, SDA, SCL> where I2C: esp_i2c_mod::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin, { pub fn new( i2c_driver: Rc<RefCell<&mut I2CDriver<I2C, SDA, SCL>>>, slave_id: u8, ) -> anyhow::Result<PwmController<I2C, SDA, SCL>> { return Ok(PwmController { i2c_driver, slave_id, }); } // PWMボードのアドレスを取得する pub fn fetch_board_addr(&self) -> String { return "not implement".to_string(); } fn test_pwm(&mut self) { let i2c_driver = Rc::clone(&self.i2c_driver); let i2c = i2c_driver.borrow_mut(); let address = Address::default(); let mut pwm = Pca9685::new(i2c.i2c_instance, address).unwrap(); // This corresponds to a frequency of 60 Hz. pwm.set_prescale(100).unwrap(); // It is necessary to enable the device. pwm.enable().unwrap(); // Turn on channel 0 at 0. pwm.set_channel_on(Channel::C0, 0).unwrap(); // Turn off channel 0 at 2047, which is 50% in // the range `[0..4095]`. pwm.set_channel_off(Channel::C0, 2047).unwrap(); let _ = pwm.destroy(); // Get the I2C device back } } impl<I2C, SDA, SCL> I2CMasterTrait for PwmController<'_, I2C, SDA, SCL> where I2C: esp_i2c_mod::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin, { fn get_id(&self) -> u8 { self.slave_id } fn exist_slave(&mut self) -> bool { let mut buffer = [0, 2]; RefCell::borrow_mut(&self.i2c_driver) .read(self.get_id(), &mut buffer) .unwrap(); println!("exist {}, buffer = {:?}", self.get_id(), buffer); return true; } }

i2c.rs

Rust

//! i2cのインスタンスを管理するクラス //! use std::{thread::sleep, time::Duration}; use anyhow::Result; use embedded_hal::prelude::_embedded_hal_blocking_i2c_Read; use esp_idf_hal::{ gpio::{InputPin, OutputPin}, i2c::{self, I2cError}, }; pub trait I2CMasterTrait { fn get_id(&self) -> u8; /// センサーが生きているかどうか fn exist_slave(&mut self) -> bool; } pub struct I2CDriver<I2C, SDA, SCL> where I2C: i2c::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin, { pub i2c_instance: i2c::Master<I2C, SDA, SCL>, } impl<I2C, SDA, SCL> I2CDriver<I2C, SDA, SCL> where I2C: i2c::I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin, { pub fn new(i2c: I2C, pins: i2c::MasterPins<SDA, SCL>) -> Result<Self> { let i2c_instance = i2c::Master::new( i2c, pins, i2c::config::MasterConfig::new().timeout(Some(Duration::from_millis(100))), ) .unwrap(); return Ok(I2CDriver { i2c_instance }); } pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cError> { if let Err(e) = self.i2c_instance.read(address, buffer) { println!("read error: {}", e); return Ok(()); } return Ok(()); } pub fn scan_address(&mut self) -> String { println!("created i2c pwm boad instance."); for address in 60..127 { println!("try address= {}", address); let mut ret = [0; 32]; if let Err(e) = self.i2c_instance.read(address, &mut ret) { println!("cant read e:{}", e); continue; } println!("Read Complete."); println!("hit i2c. addr: {:?}", address); println!("receive data = {:?}", ret); sleep(Duration::from_millis(100)); } return "finish".to_string(); } }

エラー発生箇所とエラー文

エラー文は今回の問題が発生した経緯と同じ

イメージ説明

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。