🔧

RustでFirst Class Collectionするには

2024/03/15に公開

Iteratorトレイトを実装すれば良いです。

下記のような構造体を例にしてみます。

#[derive(Debug, PartialEq)]
struct Post {
    pub content: String,
}

#[derive(Debug, PartialEq)]
struct Posts(pub Vec<Post>);

Postsに対してIteratorトレイトを実装します。
Itemの型を定義して、nextメソッドを実装するだけです。

impl Iterator for Posts {
    type Item = Post;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.pop()
    }
}

そうするとこんな感じになります。
Postsから直接mapが使えるようになっています。

#[test]
fn test_iter() {
    let posts = Posts(vec![
        Post {
            content: "aaa".into(),
        },
        Post {
            content: "aaa".into(),
        },
    ]);

    let actual = posts
        .map(|post| post.content.replace("a", "b"))
        .collect::<Vec<_>>();

    assert_eq!(vec!["bbb", "bbb"], actual);
}

この方法だとそれぞれの型に対して都度Iteratorトレイトの実装を書いてやる必要があるので、マクロを書いてあげると気持ちよさそうですね。

Iteratorトレイトに対して特定の境界を満たす場合のnextメソッドのデフォルト実装を定義できればマクロを書かずとも簡単に複数の型に対してIteratorトレイトを適用できると思うのですが、言語仕様上おそらくできない気がします。もし方法を知っている方がいたら教えて欲しいです。

マクロを書けるようになろう...

Discussion