76094


タイトルの通りのことをやろうとしたところ、以下の冗長なコードしか思いつきませんでした。  
もっとシンプルな実装方法がないかと思い質問させていただきました。  
よろしくお願いいたします。

**rust のバージョン:**

[code]

    $ rustc -V
    rustc 1.50.0 (cb75ad5db 2021-02-10)
    
[/code]

**現状のコード:**

[code]

    let src: Vec<u32> = vec![1, 2, 3];
    let add = 4_u32;
    let dst = src
        .into_iter()
        .chain(vec![add].into_iter())
        .collect::<Vec<u32>>();
    assert_eq!(dst, [1, 2, 3, 4]);
    
[/code]


CC BY-SA 4.0
2021-05-26T23:48:22.673
76091
2021-05-27T00:33:27.593
2021-05-27T00:33:27.593
3060
45509
question
rust
RustでimmutableなVecに要素を追加した新しいVecを作成する方法


まず話の前提として、タイトルに書かれていることと、提示されているコードが異なります。

タイトルでは

  * 元のVecはimmutable
  * 元のVecは残し、新たに要素を追加したVecを作成する

という意味になっています。

一方で、提示されているコードでは

  * 元のVecを解体してイテレータにして値を取り出し（into_iter）
  * イテレータに追加の値を加え（chain）
  * イテレータを新しいVecにまとめる（collect）

という処理になっています。  
つまり、提示されているコードでは新たにVecをつくってはいるものの、元のVecは残っていません。

以上を踏まえ、単純化したコードをそれぞれのパターンに対して示します。

【元のVecを残す（タイトル通り）】

[code]

    let mut dst = src.clone();
    dst.push(add);
    
[/code]

【元のVecを残さない（提示コード通り）】

[code]

    let mut dst = src;
    dst.push(add);
    
[/code]


CC BY-SA 4.0
2021-05-27T00:22:53.710
76093
2021-05-27T00:22:53.710
7748
76091
answer


`vec![add].into_iter()`は単に`vec![add]`で良いです。

[code]

    let dst = src.into_iter().chain(vec![add]).collect::<Vec<u32>>();
    
[/code]

また明示的に`Iterator`にしたいなら[`std::iter::once`](https://doc.rust-
lang.org/stable/std/iter/fn.once.html)を使うことで`iter::once(add)`のようにできます。

本題ですが、Rustではこれ以上シンプルなやりかたはあまり無いと思います。一応外部ライブラリ(といっても準標準と言ってもよい立ち位置にあります)である[`itertools`](https://docs.rs/crate/itertools)を使うとこのような書き方ができます。

1.

[code]

    let dst = itertools::concat(vec![src, vec![add]]);
    
[/code]

  2. 

[code]

    use itertools::Itertools as _;
    use std::iter;
    
    let dst = itertools::chain(src, iter::once(add)).collect_vec();
    //                              ^^^^^^^^^^^^^^^
    //                     あるいは: vec![add]
    
[/code]

またそのような操作を何度も行うなら、このような関数/拡張メソッドをいう手もあります。(`std`にあるアイテムを調べたいときは、"https://std.rs/キーワード"で検索できます。)

3.

[code]

    use std::iter;
    
    let dst = src.pushed(add);
    
    // `Extend`全般に対して実装することで、`HashSet<_>`等にも使うことができる
    trait ExtendExt<T> {
        fn pushed(self, item: T) -> Self;
    }
    
    impl<T, I: Extend<T>> ExtendExt<T> for I {
        fn pushed(mut self, item: T) -> Self {
            self.extend(iter::once(item));
            self
        }
    }
    
[/code]


CC BY-SA 4.0
2021-05-27T00:31:49.377
76094
2021-05-27T00:31:49.377
45510
76091
answer