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

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

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

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

Q&A

0回答

644閲覧

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

_filu

総合スコア0

Rust

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

0グッド

0クリップ

投稿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

1use esp_idf_hal::{ 2 gpio::{InputPin, OutputPin}, 3 i2c::{self as esp_i2c_mod}, 4}; 5use std::{cell::RefCell, rc::Rc}; 6 7use i2c_driver::i2c::I2CDriver; 8use i2c_driver::i2c::I2CMasterTrait; 9 10use anyhow; 11 12use pwm_pca9685::{Address, Channel, Pca9685}; 13 14pub struct PwmController<'i2c_driver, I2C, SDA, SCL> 15where 16 I2C: esp_i2c_mod::I2c, 17 SDA: OutputPin + InputPin, 18 SCL: OutputPin + InputPin, 19{ 20 pub i2c_driver: Rc<RefCell<&'i2c_driver mut I2CDriver<I2C, SDA, SCL>>>, 21 pub slave_id: u8, 22} 23 24impl<I2C, SDA, SCL> PwmController<'_, I2C, SDA, SCL> 25where 26 I2C: esp_i2c_mod::I2c, 27 SDA: OutputPin + InputPin, 28 SCL: OutputPin + InputPin, 29{ 30 pub fn new( 31 i2c_driver: Rc<RefCell<&mut I2CDriver<I2C, SDA, SCL>>>, 32 slave_id: u8, 33 ) -> anyhow::Result<PwmController<I2C, SDA, SCL>> { 34 return Ok(PwmController { 35 i2c_driver, 36 slave_id, 37 }); 38 } 39 // PWMボードのアドレスを取得する 40 pub fn fetch_board_addr(&self) -> String { 41 return "not implement".to_string(); 42 } 43 44 fn test_pwm(&mut self) { 45 let i2c_driver = Rc::clone(&self.i2c_driver); 46 let i2c = i2c_driver.borrow_mut(); 47 let address = Address::default(); 48 49 let mut pwm = Pca9685::new(i2c.i2c_instance, address).unwrap(); 50 // This corresponds to a frequency of 60 Hz. 51 pwm.set_prescale(100).unwrap(); 52 53 // It is necessary to enable the device. 54 pwm.enable().unwrap(); 55 56 // Turn on channel 0 at 0. 57 pwm.set_channel_on(Channel::C0, 0).unwrap(); 58 59 // Turn off channel 0 at 2047, which is 50% in 60 // the range `[0..4095]`. 61 pwm.set_channel_off(Channel::C0, 2047).unwrap(); 62 63 let _ = pwm.destroy(); // Get the I2C device back 64 } 65} 66 67impl<I2C, SDA, SCL> I2CMasterTrait for PwmController<'_, I2C, SDA, SCL> 68where 69 I2C: esp_i2c_mod::I2c, 70 SDA: OutputPin + InputPin, 71 SCL: OutputPin + InputPin, 72{ 73 fn get_id(&self) -> u8 { 74 self.slave_id 75 } 76 77 fn exist_slave(&mut self) -> bool { 78 let mut buffer = [0, 2]; 79 RefCell::borrow_mut(&self.i2c_driver) 80 .read(self.get_id(), &mut buffer) 81 .unwrap(); 82 83 println!("exist {}, buffer = {:?}", self.get_id(), buffer); 84 85 return true; 86 } 87}

i2c.rs

Rust

1//! i2cのインスタンスを管理するクラス 2//! 3 4use std::{thread::sleep, time::Duration}; 5 6use anyhow::Result; 7use embedded_hal::prelude::_embedded_hal_blocking_i2c_Read; 8use esp_idf_hal::{ 9 gpio::{InputPin, OutputPin}, 10 i2c::{self, I2cError}, 11}; 12 13pub trait I2CMasterTrait { 14 fn get_id(&self) -> u8; 15 /// センサーが生きているかどうか 16 fn exist_slave(&mut self) -> bool; 17} 18 19pub struct I2CDriver<I2C, SDA, SCL> 20where 21 I2C: i2c::I2c, 22 SDA: OutputPin + InputPin, 23 SCL: OutputPin + InputPin, 24{ 25 pub i2c_instance: i2c::Master<I2C, SDA, SCL>, 26} 27 28impl<I2C, SDA, SCL> I2CDriver<I2C, SDA, SCL> 29where 30 I2C: i2c::I2c, 31 SDA: OutputPin + InputPin, 32 SCL: OutputPin + InputPin, 33{ 34 pub fn new(i2c: I2C, pins: i2c::MasterPins<SDA, SCL>) -> Result<Self> { 35 let i2c_instance = i2c::Master::new( 36 i2c, 37 pins, 38 i2c::config::MasterConfig::new().timeout(Some(Duration::from_millis(100))), 39 ) 40 .unwrap(); 41 42 return Ok(I2CDriver { i2c_instance }); 43 } 44 45 pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cError> { 46 if let Err(e) = self.i2c_instance.read(address, buffer) { 47 println!("read error: {}", e); 48 return Ok(()); 49 } 50 return Ok(()); 51 } 52 53 pub fn scan_address(&mut self) -> String { 54 println!("created i2c pwm boad instance."); 55 56 for address in 60..127 { 57 println!("try address= {}", address); 58 59 let mut ret = [0; 32]; 60 if let Err(e) = self.i2c_instance.read(address, &mut ret) { 61 println!("cant read e:{}", e); 62 continue; 63 } 64 65 println!("Read Complete."); 66 println!("hit i2c. addr: {:?}", address); 67 println!("receive data = {:?}", ret); 68 sleep(Duration::from_millis(100)); 69 } 70 71 return "finish".to_string(); 72 } 73}

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

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

イメージ説明

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問