impl Trait - Rust By Example
Description: Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries.

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# `impl Trait`

`impl Trait`は2つの利用方法があります：

1. 引数の型
2. リターン型

## 引数の型

あなたの関数がジェネリックなトレイトを使用していて、特定の型を意識していない場合、`impl Trait`を引数の型として利用して、関数宣言をシンプルにできます。

例えば、次のコードを考えてみましょう：

    fn parse_csv_document<R: std::io::BufRead>(src: R) -> std::io::Result<Vec<Vec<String>>> {
        src.lines()
            .map(|line| {
                // ソースのそれぞれの行について
                line.map(|line| {
                    // 行を読み込んだら処理します。そうでなければエラーを返します。
                    line.split(',') // 行をカンマで分割します。
                        .map(|entry| String::from(entry.trim())) // 前後の空白を削除します。
                        .collect() // 各行の全ての文字列をVec<String>に集めます。
                })
            })
            .collect() // 全ての行をVec<Vec<String>>に集めます。
    }

`parse_csv_document`はジェネリックなので、BufReadを実装する任意の型を取ることができます。例えば、`BufReader<File>`や`[u8]`です。`R`がどんな型かは重要ではなく、`src`の型宣言に使われているだけなので、この関数は以下のように書くこともできます：

    fn parse_csv_document(src: impl std::io::BufRead) -> std::io::Result<Vec<Vec<String>>> {
        src.lines()
            .map(|line| {
                // ソースのそれぞれの行について
                line.map(|line| {
                    // 行を読み込んだら処理します。そうでなければエラーを返します。
                    line.split(',') // 行をカンマで分割します。
                        .map(|entry| String::from(entry.trim())) // 前後の空白を削除します。
                        .collect() // 各行の全ての文字列をVec<String>に集めます。
                })
            })
            .collect() // 全ての行をVec<Vec<String>>に集めます。
    }

`impl Trait`を引数の型として利用するということは、どのような形式の関数であるか明示できないので、注意してください。例えば、`parse_csv_document::<std::io::Empty>(std::io::empty())`は2番目の例では動作しません。

## リターン型

あなたの関数が`MyTrait`を実装する型を返す場合、リターン型を`-> impl MyTrait`のように書けます。これで型シグネチャをとてもシンプルにできます。

    use std::iter;
    use std::vec::IntoIter;

    // この関数は2つの`Vec<i32>を組み合わせて、そのイテレータを返します。
    // リターン型がとても複雑です！
    fn combine_vecs_explicit_return_type(
        v: Vec<i32>,
        u: Vec<i32>,
    ) -> iter::Cycle<iter::Chain<IntoIter<i32>, IntoIter<i32>>> {
        v.into_iter().chain(u.into_iter()).cycle()
    }

    // これは全く同じ関数ですが、リターン型に`impl Trait`を使っています。
    // とてもシンプルですね！
    fn combine_vecs(
        v: Vec<i32>,
        u: Vec<i32>,
    ) -> impl Iterator<Item=i32> {
        v.into_iter().chain(u.into_iter()).cycle()
    }

    fn main() {
        let v1 = vec![1, 2, 3];
        let v2 = vec![4, 5];
        let mut v3 = combine_vecs(v1, v2);
        assert_eq!(Some(1), v3.next());
        assert_eq!(Some(2), v3.next());
        assert_eq!(Some(3), v3.next());
        assert_eq!(Some(4), v3.next());
        assert_eq!(Some(5), v3.next());
        println!("all done");
    }

より重要なことに、Rustの型には書き表せないものがあるのです。例えば、あらゆるクロージャは独自の無名な具象型を持ちます。`impl Trait`構文がない時は、クロージャを返すにはヒープ上に置かねばなりませんでした。しかし今では次のようにすべて静的に行えます。

    // 入力に`y`を加える関数を返します。
    fn make_adder_function(y: i32) -> impl Fn(i32) -> i32 {
        let closure = move |x: i32| { x + y };
        closure
    }

    fn main() {
        let plus_one = make_adder_function(1);
        assert_eq!(plus_one(2), 3);
    }

`impl Trait`を使って、`map`や`filter`クロージャを使うイテレータを返すこともできます。おかげで`map`や`filter`を簡単に使えます。クロージャ型は名前を持たないので、あなたの関数がクロージャを持つイテレータを返す場合、明示的なリターン型を書くことはできません。しかし`impl Trait`を使うことで簡単にできます：

    fn double_positives<'a>(numbers: &'a Vec<i32>) -> impl Iterator<Item = i32> + 'a {
        numbers
            .iter()
            .filter(|x| x > &&0)
            .map(|x| x * 2)
    }

    fn main() {
        let singles = vec![-3, -2, 2, 3];
        let doubles = double_positives(&singles);
        assert_eq!(doubles.collect::<Vec<i32>>(), vec![4, 6]);
    }