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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Rust

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

解決済

【Rust】クロージャ(ラムダ)に絡むコードがRubyなら簡単に動くがRustではコンパイルエラーになるのを解決したい。

akira_kano1101
akira_kano1101

総合スコア16

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Rust

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

1回答

0評価

1クリップ

391閲覧

投稿2022/04/03 11:48

編集2022/04/06 12:38

Rubyなら簡単に動かせるコードをRustでも実現したい

こんにちは。Rustでソフトウェアを開発しています。

問題が二つあるので簡単に説明します。まずは記事中「問題のRustのコード」を確認していただきたいのですが、

  • (*self.renderer)()でクロージャ実行をしたいが共有参照&mutが関与しているのが原因なのかFのムーブが関与しているのが原因なのか、型サイズが不明なのが原因なのか、クロージャが呼べません。
  • ライフタイムの関係でクロージャ内の一時変数がドロップされるのが理由なのか、構造体にそのクロージャを持たせたいのですが上手くできません。(こちらの方が特に問題)

これらを解決したいです。

検証のため問題を再現した最小のRustのコードを以下に用意しました。

もしご存じの方いらっしゃれば教えていただけないでしょうか。

(Rubyでは実行できることを確認したので追記しました。)

本題

動作するRubyのコード

Rubyでなら同じ問題は起こりません。

ruby

class Card def initialize(renderer) @renderer = renderer end def render @renderer[] end end class Presenter def get "Message" end end class App def initialize @presenter = Presenter.new @card = Card.new(->() { "" }) end def setup @presenter = Presenter.new @card = Card.new(->() { @presenter.get() }) end def update puts @card.render # => "Message"と表示される end end def main app = App.new app.setup app.update end main

問題のRustのコード(検証用)

そしてこちらが問題です。

rust

struct Presenter; impl Presenter { pub fn get(&self) -> String { "Message".to_string() } } struct Card<'a, F> where F: ?Sized + FnOnce() -> String, { renderer: &'a F, } impl<'a, F> Card<'a, F> where F: ?Sized + FnOnce() -> String, { pub fn new(renderer: &'a F) -> Self { Self { renderer: renderer } } pub fn render(&self) -> String { (*self.renderer)() // コンパイルエラー } } struct App<'a> { presenter: Presenter, card: Card<'a, dyn FnOnce() -> String>, } impl<'a> App<'a> { pub fn new() -> Self { Self { presenter: Presenter, card: Card::new(&|| "".to_string()), } } pub fn setup(&mut self) { self.card = Card::new(&|| self.presenter.get()); // コンパイルエラー } pub fn update(&mut self) { println!("{:?}", self.card.render()); } } fn main() { let mut app = App::new(); app.setup(); app.update(); }

エラーメッセージ抜粋

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

ご回答のほどよろしくお願いいたします。

良い質問の評価を上げる

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

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

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

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

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

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

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

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

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

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

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

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

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Rust

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