Home > front end >  Equivalent of `std::iter::inspect` for method chains
Equivalent of `std::iter::inspect` for method chains

Time:07-02

In rust, is it possible to inspect the intermediate values in a chain of method calls? The equivalent method exists for iterators so that the values produced may be inspected before being passed to the next iterator in the chain. Essentially, I'm looking for something like this:

impl<T> T {
    fn inspect(&self, f: impl Fn(&Self)) -> &Self {
        f(&self);
        &self
    }
}

// ...

object
    .a()
    .inspect(|x| println!("after a(): {:?}", x))
    .b()
    .inspect(|x| println!("after b(): {:?}", x))
    .c();

The purpose is to aid in debugging a long chain of function calls; currently the only solution is to break up the chain with an assignment to a variable, print the variable, and then continue on with the rest of the chain.

Does something like this exist? I believe the orphan rules would forbid one from implementing it themself in general.

CodePudding user response:

You can define a trait for this almost exactly like that:

trait Inspect {
    fn inspect(self, f: impl Fn(&Self)) -> Self;
}

impl<T> Inspect for T {
    fn inspect(self, f: impl Fn(&Self)) -> Self {
        f(&self);
        self
    }
}

I modified it a bit to pass self by value to make it more flexible. It will work with &T/&mut T and return &T/&mut T.

Test:

#[derive(Debug)]
struct Foo {}

impl Foo {
    fn a(&self) -> &Self {
        self
    }
    fn b(&self) -> &Self {
        self
    }
    fn c(&self) -> &Self {
        self
    }
}

fn main() {
    Foo {}
        .a()
        .inspect(|x| println!("after a(): {:?}", x))
        .b()
        .inspect(|x| println!("after b(): {:?}", x))
        .c();
}

Output:

after a(): Foo
after b(): Foo

Playground


Test for mutable value:

#[derive(Debug, Default)]
struct Foo {
    value: i32,
}

impl Foo {
    fn a(&mut self) -> &mut Self {
        self.value  = 1;
        self
    }
    fn b(&mut self) -> &mut Self {
        self.value  = 2;
        self
    }
}

fn main() {
    Foo::default()
        .a()
        .inspect(|x| println!("after a(): {:?}", x))
        .b()
        .inspect(|x| println!("after b(): {:?}", x));
}

Output:

after a(): Foo { value: 1 }
after b(): Foo { value: 3 }

Playground

  • Related