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

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

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

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

Q&A

解決済

1回答

242閲覧

クロージャが FnOnce トレイト止まりに推論される場合

Eki

総合スコア429

Rust

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

1グッド

0クリップ

投稿2018/02/28 19:09

次のようなコードを考えます。

rust

1struct S { 2 a: Box<i32>, 3 b: Box<i32>, 4} 5 6fn main() { 7 let s = S { 8 a: Box::new(1), 9 b: Box::new(2), 10 }; 11 let _closure = || { let _sa = s.a; }; // エラー 12}

このとき エラー の行で

error[E0507]: cannot move out of captured outer variable in an `Fn` closure --> /home/dai/workspace/daily/2018/0301/junk03-51-57.rs:11:35 | 11 | let _closure = || { let _sa = s.a; }; | ^-- | | | cannot move out of captured outer variable in an `Fn` closure | help: consider using a reference instead: `&s.a` error: aborting due to previous error

とエラーになります。コンパイラは s の借用で済むと判断して、クロージャに Fn まで実装したところ、 Fn クロージャの中で借用した値をムーブしようとしているためにエラーになっているようです。

しかし、 s.a をムーブしようとした段階で s のムーブが必要な (あるいは _sa に相当する形で s.a だけを部分的にムーブする必要がある) ことはコンパイラには分かると思います。そういう形で環境に所有権を移してしまって FnOnce 止まりに推論すればよい気がします。さらに不思議なことは、move をつけて明示的にムーブを指示しても s をムーブしてくれませんでした。

このクロージャを次のように明示的に s を取るように書き換えると

rust

1let _closure = || { 2 let s = s; 3 let _sa = s.a; 4};

無事コンパイルが通るようになりました。

このような挙動になっているのは何故なのでしょうか。
s.a だけをムーブしようとして、間違えて s ごとムーブしてしまうことを防ぐため?
それを防ぐ意味も分かりませんが、だとすれば前述の通り部分的にムーブすることでも達成できると思います。
あるいは、このようにしなければ都合の悪いことがあるのでしょうか。

carrotRakko👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

最初の例のコードはRust 1.23.0以降ならコンパイルが通るようです。

text

1$ rustc +1.22.0 main.rs 2error[E0507]: cannot move out of captured outer variable in an `Fn` closure 3 --> main.rs:11:35 4 | 511 | let _closure = || { let _sa = s.a; }; // エラー 6 | ^-- 7 | | 8 | cannot move out of captured outer variable in an `Fn` closure 9 | help: consider using a reference instead: `&s.a` 10 11error: aborting due to previous error 12 13$ rustc +1.23.0 main.rs 14$

恐らく、これはissue #30046: Closure inference fails to infer that move is required when pattern matchingで議論されていた問題の一部でしょう。つまり、意図された挙動ではなさそうです。

上に示したように最新のRustでは修正されているので、特別の事情がなければコンパイラをアップデートしておけば問題ないでしょう。

投稿2018/02/28 23:26

tesaguri

総合スコア33

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

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

Eki

2018/03/01 00:10

たしかに...手元環境が rustc 1.22.0-nightly (b633341c4 2017-10-20) でした...最新にするのを怠っていました。 なるほど。ご指摘、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問