63794


Rustで二次元ベクトルをイテレートするとき、変数にunpackして格納したいです。  
次のコードはエラーとなります。

[code]

    fn main() {
        let mut a: Vec<Vec<i32>> = Vec::new();
        a.push(Vec::new());
        a.push(Vec::new());
        for i in 0..2{
            for j in 0..3{
                a[i].push((3*i+j) as i32);
            }
        }
        println!("{:?}", a);
        for x,y,z in a{
            println!("{} {} {}", x, y, z);
        }
    }
    
[/code]

error

[code]

       |
    11 |     for x,y,z in a{
       |          ^
       |
    help: try adding parentheses to match on a tuple..
       |
    11 |     for (x,y,z) in a{
       |         ^^^^^^^
    help: ..or a vertical bar to match on multiple alternatives
       |
    11 |     for x |y |z in a{
       |         ^^^^^^^
    
[/code]

error文にあるように(x,y,z)とするとこれはタプルとして扱われるためエラーに、x |y |xとしてもエラーになってしまいます。

[code]

       |
    11 |     for (x,y,z) in a{
       |         ^^^^^^^ expected struct `std::vec::Vec`, found tuple
       |
       = note: expected struct `std::vec::Vec<i32>`
                   found tuple `(_, _, _)`
    
[/code]

どのようにすればよいのでしょうか？それとも次のように変数aiを介さないといけないのでしょうか？

[code]

    fn main() {
        let mut a: Vec<Vec<i32>> = Vec::new();
        a.push(Vec::new());
        a.push(Vec::new());
        for i in 0..2{
            for j in 0..3{
                a[i].push((3*i+j) as i32);
            }
        }
        for ai in a{
            let (x,y,z) = (ai[0],ai[1],ai[2]);
            println!("{} {} {}", x, y, z);
        }
    }
    
[/code]


CC BY-SA 4.0
2020-03-12T10:53:17.330
63792
2020-03-12T12:30:59.087
2020-03-12T11:25:13.660
20533
question
rust
rustで二次元vectorをfor文でunpackして受け取るには？


こんにちは。

回答の前に前提として、Rustの標準ライブラリに「2次元ベクトル」という型はありません。`Vec<Vec<T>>`
という型が表現しているのは「ベクトルのベクトル」です。  
どういうことかというと、以下のように長さが不揃いなベクトルも格納できるということです。

[code]

    let a = vec![
      vec![],
      vec![1, 2],
      vec![10, 20, 30]
    ];
    
[/code]

なので今回の `for x, y, z in ...` ように要素数を決め打ちにした分解はできません。

という前提の下、書き方を工夫すればやりたいことが実現できます。

## 1\. タプル or 配列にする

長さが揃っている場合の解決策です。長さが決まった型を使います。

もし2次元目のベクトルの要素数が固定ならベクトルではなくタプルにするとパターンマッチで取り出せます

[code]

    // aの型は Vec<(i32, i32, i32)>
    let a = vec! [(0, 1, 2), (3, 4, 5)];
    
    // タプルパターンで取り出せる
    for (x, y, z) in a {
        println!("{} {} {}", x, y, z);
    }
    
[/code]

あるいは、（ベクトル（`Vec<T>`） ではなく）配列 （`[T; N]`） でもパターンマッチで取り出せます

[code]

    // aの型は Vec<[i32; 3]>
    let a = vec![[0, 1, 2], [3, 4, 5]];
    
    // 配列パターンで取り出せる
    for [x, y, z] in a {
        println!("{} {} {}", x, y, z);
    }
    
[/code]

## 2\. ベクトルのまま頑張る

長さが不揃いな場合の解決策です。

操作性などの理由でベクトル
（`Vec<T>`）を使いたいのであれば、一旦変数で受けたあとに、スライスパターンでマッチする手があります。これは先程説明したとおりに長さが異なる場合を考慮したコードを書かなければなりません。

[code]

    let a = vec![vec![0, 1, 2], vec![3, 4, 5]];
    
    for v in a {
        match &v.as_slice() {
            [x, y, z] => println!("{} {} {}", x, y, z),
            // 長さが3以外の要素があった場合は想定外として、そのままプログラムを終了する
            _ => unreachable!("size of 2nd dimension must be 3"),
        }
    }
    
[/code]

以上のどちらかの方法でやりたいことが実現できるのではないかと思います。

余談ですがデータ型を分解する操作はRustでは「パターンマッチ」や「分配束縛（destructuring
bind）」と呼ばれるので、次回以降に質問するときはこの用語を使うとスムーズに回答が得られるかと思います。


CC BY-SA 4.0
2020-03-12T12:30:59.087
63794
2020-03-12T12:30:59.087
22816
63792
answer