🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Rust

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

Q&A

解決済

2回答

2919閲覧

Rustの同一スコープ内で複数の可変変数を扱うことについて

TS01

総合スコア3

Rust

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

0グッド

0クリップ

投稿2020/12/18 20:55

Rustのドキュメントを読んで勉強中です。
ドキュメント上では、「可変な参照には大きな制約が一つあります: 特定のスコープで、ある特定のデータに対しては、 一つしか可変な参照を持てないことです。」
とのことですが、以下のコードではコンパイルエラーになりません。
なぜでしょうか?

該当のソースコード

Rust

1fn main() { 2 let mut s = String::from("test"); 3 4 let s1 = &mut s; 5 let s2 = &mut s; 6 7 println!("{}", s2); 8}

また、以下の場合では、望むエラーが出ます。

Rust

1fn main() { 2 let mut s = String::from("test"); 3 4 let s1 = &mut s; 5 6 let s2 = &mut s; 7 8 println!("{}", s1); 9}

エラーメッセージ

warning: unused variable: `s2` --> src/main.rs:6:9 | 6 | let s2 = &mut s; | ^^ help: if this is intentional, prefix it with an underscore: `_s2` | = note: `#[warn(unused_variables)]` on by default error[E0499]: cannot borrow `s` as mutable more than once at a time --> src/main.rs:6:14 | 4 | let s1 = &mut s; | ------ first mutable borrow occurs here 5 | 6 | let s2 = &mut s; | ^^^^^^ second mutable borrow occurs here 7 | 8 | println!("{}", s1); | -- first borrow later used here error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0499`. error: could not compile `pr2`

いずれにしても、同じように同一スコープ内で可変な参照を2つ持っているのでコンパイルエラーとなるものと思っていたのですが。。

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

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

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

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

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

guest

回答2

0

ベストアンサー

Rustコンパイラは参照が使われている場所の情報を参照のオーバーラップしているかの判定に使います.
ですので,最初のコードの場合は

rust

1fn main() { 2 let mut s = String::from("test"); 3 4 let s1 = &mut s; // 1つ目の可変参照はここだけで使われている 5 6 let s2 = &mut s; // 2つ目はここで使う 7 println!("{}", s2); // 2つ目 8}

となり,1つ目の可変参照と2つ目の可変参照が使われている区間がオーバーラップしないので可変参照の唯一性を破らないとコンパイラが判定します.

一方で,次のコードの場合は

rust

1fn main() { 2 let mut s = String::from("test"); 3 4 let s1 = &mut s; // ①: 1つ目 5 6 let s2 = &mut s; // ②: 1つ目 + 2つ目 ← オーバーラップ! 7 8 println!("{}", s1); // ③: 1つ目 9}

1つ目の可変参照は①で作られて③で使用されているので,②の時点でも有効であるとみなされます.
これは2つ目の可変参照の区間とオーバーラップするので,コンパイルエラーです.

このような使用箇所に応じた高度なチェックはNon-lexical lifetime(NLL)と呼ばれ,2018年から実装されています.

投稿2020/12/19 02:24

pandaman64

総合スコア26

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

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

TS01

2020/12/19 07:43

区間のオーバーラップについて、よく理解できました。 ありがとうございました。
guest

0

変数の定義は参照ではなく、変数を利用しようとする部分が参照だと考えると矛盾はしないですが、何故そうなのかはわからないです。

投稿2020/12/18 22:01

rysh

総合スコア874

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問