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

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

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

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Rust

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

Q&A

解決済

1回答

1603閲覧

【Rust】関数内で所有権が移動されたオブジェクトをcloneメソッドを使わずに外部に取り出したい

akira_kano1101

総合スコア25

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Rust

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

0グッド

0クリップ

投稿2022/03/24 10:22

編集2022/03/24 11:40

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

Rustで関数の内側で作られたオブジェクトは外側に持ち出せないのかどうか簡単なケースで検証を行なっています。

問題のソースコード

rust

1use std::sync::{Arc, Mutex}; 2 3 #[derive(Clone)] 4 struct Foo { 5 x: i32, 6 } 7 8 fn handle_with_clone(from: Arc<Mutex<Foo>>) -> Foo { 9 (*from.lock().unwrap()).clone() } 10 fn handle_without_clone(from: Arc<Mutex<Foo>>) -> Foo { 11 *from.lock().unwrap() // コンパイルエラー 12 } 13 14 fn main() { 15 let x = Arc::new(Mutex::new(Foo { x: 1 })); 16 17 let y = handle_with_clone(Arc::clone(&x)); 18 let z = handle_without_clone(Arc::clone(&x)); 19 }

エラーメッセージ抜粋

error[E0507]: cannot move out of dereference of `MutexGuard<'_, Foo>` --> src/main.rs:12:5 | 12 | *from.lock().unwrap() | ^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait

関数内でclone()メソッドを使うと値が取り出せるのですが、cloneでディープコピーを行いたくない場合、どう実装を書けばよいかわかりません。

ご存じの方もしいらっしゃれば、恐縮ですが教えていただけないでしょうか?

よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

状況を簡単にするためにここでは Mutex を無視して Arc だけで説明します。 質問者の例と同様にエラーになります。

rust

1use std::sync::Arc; 2 3#[derive(Clone)] 4struct Foo { 5 x: i32, 6} 7 8fn handle(from: Arc<Foo>) -> Foo { 9 *from // ここでエラー 10} 11 12fn main() { 13 let x = Arc::new(Foo { x: 1 }); 14 let z = handle(x.clone()); 15}

Foo のオブジェクトはスマートポインタ (Arc) の管理下にあります。

  • Arc は参照カウント方式のスマートポインタなのでカウント外で参照が存在すると破綻してしまう
  • Arc はそれが指すオブジェクトを他のスマートポインタと共有する可能性があるので (ポインタが指すオブジェクトを) ムーブできないようになっている (ムーブしたら破綻する)
  • スマートポインタの管理下にない同内容のオブジェクトを作るのであればそれは複製である

という理由で、この場合は複製せずに関数の外に持ち出すことは出来ないことになります。

これが Arc から Box に置き換えるだけでムーブが可能になるのでエラーは消えます。

rust

1#[derive(Clone)] 2struct Foo { 3 x: i32, 4} 5 6fn handle(from: Box<Foo>) -> Foo { 7 *from 8} 9 10fn main() { 11 let x = Box::new(Foo { x: 1 }); 12 let z = handle(x.clone()); 13}

Box はそれが指す内容を他のポインタと共有しない唯一無二のものなので共有の可能性がなく、ムーブを許すと同時にポインタが無効になるなら破綻しないからです。 しかし Boxclone した場合にはそれが指すオブジェクトも同時に複製されることには気を付けてください。

質問者がやりたいことを私なりに推測してコードにするならおそらくこういうことではないでしょうか。

rust

1use std::sync::{Arc, Mutex, MutexGuard}; 2 3#[derive(Clone)] 4struct Foo { 5 x: i32, 6} 7 8fn handle_without_clone(from: &Arc<Mutex<Foo>>) -> MutexGuard<'_, Foo> { 9 from.lock().unwrap() 10} 11 12fn main() { 13 let x = Arc::new(Mutex::new(Foo { x: 1 })); 14 let z = handle_without_clone(&x); 15 println!("{}", z.x) 16}

投稿2022/03/29 06:23

SaitoAtsushi

総合スコア5444

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

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

akira_kano1101

2022/03/29 09:46

SaitoAtsushi様 ご回答ありがとうございます。 親切に説明してくださったおかげでRustのスマートポインタについての私の知識が深まりました。 今回は何らかの変換の詳細を隠蔽したい質問だったので推測、教えていただいた内容は答えとして問題ないと思います。 たまたま例がArcだったのですが、他の場合にもリファレンスを使えば解決できるかもしれないと思いました。 それにしてもArcが参照カウントなのに&をつけてさらにリファレンスにするなんて、何だか面白いですね。 わかりやすく説明、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問