impl Trait

もし関数が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 Traitmapfilterなどのクロージャを使ったイテレータを返すのにも 使えます! これによって、mapfilterを簡単に使えるようになります。以前はクロージャ の型は名前を持たないため、クロージャを使ったイテレータは、明示的に返り値の型が書けなかった ものが、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)
}