Implementing each iterator with trait and generics

Hi, I'm learning Rust for 1 day and I would like to implement my own .each iterator.

It should work similar to JavaScript version where you can call each on an array and it will simply loop over the items.

// JavaScript version
let values = [1,2,3,4,5];
values.each((item) => {
   console.log('Value: ', item);
});

I know in rust, you would normally do a for loop

let values = vec![1,2,3,4,5];
for item in values {
  println!("Value: {}", item);
}

but for a learning purpose I want to implement it like this.

I was able to make it work for vector of integers, but I have a trouble to implement it with generics, so it can work with anything that's iterable.

fn main() {
    let values = vec![1, 2, 3];
    values.each(|item| println!("Value: {}", item));
}

pub trait Each {
    fn each<F>(&self, f: F)
    where
        F: Fn(i32) -> ();
}

impl Each for Vec<i32> {
    fn each<F>(&self, f: F)
    where
        F: Fn(i32) -> (),
    {
        for &value in self {
            f(value);
        }
    }
}

Bonus would be if I could chain iterator calls on top of each to make something like this possible

fn main() {
    let values = vec![1, 2, 3];
    values
        .iter()
        .each(|item| println!("Before: {}", item))
        .map(|item| item * 10)
        .each(|item| println!("After {}", item))
        .collect();
}

Thanks for help :pray:

https://doc.rust-lang.org/stable/src/core/iter/iterator.rs.html#550-554

The standard library's Iterator trait has a generic parameter Item where you are using i32 in your example (line 43). Other than that, your implementation is not that different from the one in std

1 Like

You'll have to decide which semantics you want: let each consume the item, which is what the standard for_each does, or let it inspect the items, which is what the standard inspect does. The chaining you're showing at the end is only possible with the latter.

2 Likes

Thanks for the links. The inspect is basically what I was looking for. But although I know how to use it, I still have a hard time to make my own implementation. What would the code look like for a trait print_debug that accepts a string and then prints every element on screen with that string?

let values = vec![1, 2, 3];
values
    .iter()
    .print_debug("Before")
    .map(|item| item * 10)
    .print_debug("After")
    .collect();

// expected output
// Before 1
// After 10
// Before 2
// After 20
// Before 3
// After 30

To attach a trait to an existing trait you can do something like this.

// in some other crate (including std/core)

/// This trait has existing implementations
trait OtherTrait {}
// in your crate

use other_crate::OtherTrait;

trait ExtensionTrait: OtherTrait {}

impl<T: OtherTrait> ExtensionTrait for T {
    // put you functions here!
}

Yes, that's possible.

1 Like

Awesome, thank you!