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

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

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

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

Q&A

解決済

2回答

2807閲覧

for x in v.iter_mut() 内で v 全体を表示したい

Eki

総合スコア429

Rust

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

1グッド

0クリップ

投稿2017/03/15 15:34

最初に各人が数字を一つ決めて、ある人から時計まわりに「自分の数字に前の人の数字を足し、その和の一の位を新たに自分の数字とする」という「操作」を繰り返すゲームがあるとして、それを実装するとすれば単純に考えると

Rust

1 let mut players: Vec<i64> = vec![1, 2, 3, 4, 5]; 2 3 let mut prev = players[players.len() - 1]; 4 for x in players.iter_mut() { 5 *x += prev; 6 *x %= 10; 7 prev = *x; 8 } 9 println!("{:?}", players);

このようになるのですが、これだと一巡した後の結果しか表示できません。
ゲームとしては「操作」が一回行われるごとに画面に各人の情報を表示したいのですが(たとえば「自分の数字が0になった人は脱落」というルールを加えるとすると、ゲームの進行を見せるために画面の更新は一回の「操作」ごとに行われるほうが自然だと思います)、

Rust

1 for x in players.iter_mut() { 2 *x += prev; 3 *x %= 10; 4 prev = *x; 5 println!("{:?}", players); 6 }

とするのでは Rust の借用チェッカが満足しません。「操作」一回ごとに全体を出力するためには

Rust

1 for i in 0..players.len() { 2 players[i] += prev; 3 players[i] %= 10; 4 prev = players[i]; 5 println!("{:?}", players); 6 }

というようにミュータブルな参照を限定的にしか取らない(C言語的な)ループを使用するしかないのでしょうか?
あるいはこのような場合にループを利用することは不適切なのでしょうか。

Rust のバージョン

$ rustup show Default host: x86_64-unknown-linux-gnu installed toolchains -------------------- stable-x86_64-unknown-linux-gnu nightly-x86_64-unknown-linux-gnu (default) active toolchain ---------------- nightly-x86_64-unknown-linux-gnu (default) rustc 1.17.0-nightly (62eb6056d 2017-02-15)
tatsuya6502👍を押しています

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

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

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

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

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

guest

回答2

0

おそらくインデックスでアクセスするのが最善です。
あるコンテナに対して安全に操作毎に全体を表示させるにはiter_mut()だけでは不十分です。
(アルゴリズムを変更する余地はあるかもしれません)
あなたの行いたい操作はiteration毎にplayersを&mut束縛して解放する必要がありますが、iter_mut()は束縛が大雑把すぎます。

解決策としては以下の2通りが考えられます:

  1. BorrowCheckを実行時まで延期する(Cellを使う)
  2. きめ細やかな束縛を用いる(IndexMut, つまりインデックスによるアクセスを使う)

iter_mutによる束縛とindex_mutによる束縛は全く別の特性を持つものなので

(C言語的な)ループ

のように忌避せずに、状況に応じて使い分けるのが良いと思います。

投稿2017/03/16 06:40

編集2017/03/16 07:47
termoshtt

総合スコア136

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

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

Eki

2017/03/16 06:52

詳しい回答ありがとうございます。やはりインデックスによるアクセスでそのたびごとに借用を作るのが最も簡単なのですね。 配列を二つ用意する、というのは結局二つの配列を更新する必要があって同じことなのかなと思いますが、どういう方法がありますか?
termoshtt

2017/03/16 07:46

更新した値を配列に入れていくといけるような気がしたのですが、結局IndexMutでアクセスしているので同じになってしまいました。なので該当のコメントは消しておきます。
guest

0

ベストアンサー

Cell<i64>によるInterior Mutabilityで下記のように書くこともできますが、素直にインデクス値を使った方がマシかもしれませんね...

rust

1use std::cell::Cell; 2 3fn main() 4{ 5 let players: Vec<Cell<i64>> = vec![1, 2, 3, 4, 5].into_iter().map(Cell::new).collect(); 6 7 let mut prev : i64 = players[players.len() - 1].get(); 8 for x in &players { 9 let mut v : i64 = x.get(); 10 v += prev; 11 v %= 10; 12 x.set(v); 13 prev = v; 14 println!("{:?}", players.iter().map(Cell::get).collect::<Vec<_>>()); 15 } 16}

投稿2017/03/16 01:03

編集2017/03/16 01:18
yohhoy

総合スコア6191

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

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

Eki

2017/03/16 02:31

回答、ありがとうございます! たしかに面倒ですね・・・おとなしくインデックスでアクセスします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問