課題:I2Cバスで制御するドライバを書いていたが、どうしてもGPIOの方向を変えるコードをstruct型に閉じ込めた変数で実装することができなかった(借用のselfとデータの移動との矛盾が解消できず)
解決策:メソッド実行時、借用のselfではなく、所有権付きのselfを渡してメソッドでselfに再代入を行うことで、上記エラーが解消できた。このままだとselfの?所有権がメソッドに行きっぱなしになるので、呼び出し元にselfを返却する。メソッドから帰ってきたselfの実体を変数に再代入してもらうことで、所有権が戻るようにした。このコードが以下
use anyhow::Result; use esp_idf_svc::hal::gpio::{PinDriver, Pin, Output, Input, Level,Gpio2, Gpio3}; //use esp_idf_svc::hal::gpio::Level::{Low, High}; use esp_idf_svc::hal::peripherals::Peripherals; use esp_idf_svc::sys::link_patches; //use std::{thread::sleep, time::Duration}; struct I2CBus<'a, >{ scl: PinDriver<'a, Gpio2, Output> , sda: PinDriver<'a, Gpio3, Output> , } impl I2CBus<'_> { fn send(mut self)->Self{ self.scl.set_low(); let sda_in = self.sda.into_input().unwrap(); self.sda = sda_in.into_output().unwrap(); self } } fn main() -> Result<()> { link_patches(); esp_idf_svc::log::EspLogger::initialize_default(); let peripherals = Peripherals::take()?; let mut i2c_bus = I2CBus{ scl: PinDriver::output(peripherals.pins.gpio2)?, sda: PinDriver::output(peripherals.pins.gpio3)?, }; loop{ i2c_bus = i2c_bus.send(); } }
上記のようにstructにI2Cを制御するscl, sdaを閉じ込め、scl, sdaの操作はメソッドにまとめることで、本来のオブジェクト指向風にドライバが実装できる。これまでのように、GPIOの実体をサブルーチンから戻してもらうようなコードを書かなくてもよくなる。