Rubyなら簡単に動かせるコードをRustでも実現したい
こんにちは。Rustでソフトウェアを開発しています。
問題が二つあるので簡単に説明します。まずは記事中「問題のRustのコード」を確認していただきたいのですが、
(*self.renderer)()
でクロージャ実行をしたいが共有参照&mut
が関与しているのが原因なのかF
のムーブが関与しているのが原因なのか、型サイズが不明なのが原因なのか、クロージャが呼べません。- ライフタイムの関係でクロージャ内の一時変数がドロップされるのが理由なのか、構造体にそのクロージャを持たせたいのですが上手くできません。(こちらの方が特に問題)
これらを解決したいです。
検証のため問題を再現した最小のRustのコードを以下に用意しました。
もしご存じの方いらっしゃれば教えていただけないでしょうか。
(Rubyでは実行できることを確認したので追記しました。)
本題
動作するRubyのコード
Rubyでなら同じ問題は起こりません。
ruby
1class Card 2 def initialize(renderer) 3 @renderer = renderer 4 end 5 def render 6 @renderer[] 7 end 8end 9 10class Presenter 11 def get 12 "Message" 13 end 14end 15 16class App 17 def initialize 18 @presenter = Presenter.new 19 @card = Card.new(->() { "" }) 20 end 21 def setup 22 @presenter = Presenter.new 23 @card = Card.new(->() { @presenter.get() }) 24 end 25 def update 26 puts @card.render # => "Message"と表示される 27 end 28end 29 30def main 31 app = App.new 32 app.setup 33 app.update 34end 35 36main
問題のRustのコード(検証用)
そしてこちらが問題です。
rust
1struct Presenter; 2 3impl Presenter { 4 pub fn get(&self) -> String { 5 "Message".to_string() 6 } 7} 8 9struct Card<'a, F> 10where 11 F: ?Sized + FnOnce() -> String, 12{ 13 renderer: &'a F, 14} 15 16impl<'a, F> Card<'a, F> 17where 18 F: ?Sized + FnOnce() -> String, 19{ 20 pub fn new(renderer: &'a F) -> Self { 21 Self { renderer: renderer } 22 } 23 pub fn render(&self) -> String { 24 (*self.renderer)() // コンパイルエラー 25 } 26} 27 28struct App<'a> { 29 presenter: Presenter, 30 card: Card<'a, dyn FnOnce() -> String>, 31} 32 33impl<'a> App<'a> { 34 pub fn new() -> Self { 35 Self { 36 presenter: Presenter, 37 card: Card::new(&|| "".to_string()), 38 } 39 } 40 pub fn setup(&mut self) { 41 self.card = Card::new(&|| self.presenter.get()); // コンパイルエラー 42 } 43 pub fn update(&mut self) { 44 println!("{:?}", self.card.render()); 45 } 46} 47 48fn main() { 49 let mut app = App::new(); 50 app.setup(); 51 app.update(); 52}
エラーメッセージ抜粋
error[E0161]: cannot move a value of type F: the size of F cannot be statically determined --> src/main.rs:24:9 | 24 | (*self.renderer)() | ^^^^^^^^^^^^^^^^ error[E0507]: cannot move out of `*self.renderer` which is behind a shared reference --> src/main.rs:24:9 | 24 | (*self.renderer)() | ^^^^^^^^^^^^^^^^ move occurs because `*self.renderer` has type `F`, which does not implement the `Copy` trait error: lifetime may not live long enough --> src/main.rs:41:31 | 40 | pub fn setup(&mut self) { | - let's call the lifetime of this reference `'1` 41 | self.card = Card::new(&|| self.presenter.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static` error[E0716]: temporary value dropped while borrowed --> src/main.rs:41:32 | 33 | impl<'a> App<'a> { | -- lifetime `'a` defined here ... 41 | self.card = Card::new(&|| self.presenter.get()); | -----------------------^^^^^^^^^^^^^^^^^^^^^^^- | | | | | creates a temporary which is freed while still in use | assignment requires that borrow lasts for `'a` 42 | } | - temporary value is freed at the end of this statement
ご回答のほどよろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/04/06 03:38