It's a simple wrapper to turn any method into a chainable method, or to opt-in to a builder-pattern API. Vec::sort returns unit, so you can't say Iterator::collect::<Vec<_>>().sort().into_iter() to sort an iterator and resume iteration, because sort doesn't return self!
-
Show this thread
-
You can, however, do collect::<Vec<_>>().tap(|v| v.sort()).into_iter() because tap DOES return self. It specifically takes self, borrows it into the given function, and returns self after the function ends. This does mean you can't tap functions that take self by value.
3 replies 1 retweet 20 likesShow this thread -
But because bare tap, blindly taking and lending the value, is booooring and doesn't play nicely with common Rust patterns, the Rust tap crate also has variants that know how to work with types like bool, Option, Result, and Future.
1 reply 0 retweets 5 likesShow this thread -
This means you don't have to match the right variant inside the tap, you can just use a different tap function! We offer tap_{true,false} on bool, tap_{some,none} on Option, and tap_{ok,err} on Result. I don't remember the Future API; I think I need to update it.
1 reply 0 retweets 3 likesShow this thread -
These taps do the inspection for you, so the closure can expect the interior value and the closure will only run if the wrapper is of the correct type. tap_ok takes a closure that takes the T type of Result, not Result
1 reply 0 retweets 2 likesShow this thread -
And you can tap *anything*; we blanket implement it on all types. You can casually attach behavior to any value, anywhere, transparently. This is useful for things like temporary mutability
1 reply 0 retweets 3 likesShow this thread -
To sort a vector, you would ordinarily have to let mut v: Vec<T> = Iterator::collect(); v.sort(); let v = v; // freeze But tap lets you do let v: Vec<T> = Iterator::collect().tap(|v| v.sort()); no temporary binding needed
1 reply 2 retweets 12 likesShow this thread -
TLDR, it's a `map()` that automatically returns the value you give to it, no matter what function you pass in, and it also exists everywhere instead of just on carrier types. It's great for method chains, or for modifying an expression without requiring an intermediate binding.
3 replies 0 retweets 10 likesShow this thread -
The tap crate, btw, is https://crates.io/crates/tap . The original is https://github.com/darfink/tap-rs and I maintain a fork at https://github.com/myrrlyn/tap-rs that is slightly less inactive.
1 reply 0 retweets 9 likesShow this thread -
Replying to @myrrlyn
This would be really cool to add to std; has it been brought up before?
1 reply 0 retweets 2 likes
(I'm guessing the answer is: definitely -- but curious if there's been discussion about it on internals, or even more than that! :D)
-
-
Replying to @yoshuawuyts
No idea. Rust keeps a lot of things out of std and I'm pretty okay with that it just means evangelism work is needed. Though to be fair this is true of std modules also
0 replies 0 retweets 1 likeThanks. Twitter will use this to make your timeline better. UndoUndo
-
Loading seems to be taking a while.
Twitter may be over capacity or experiencing a momentary hiccup. Try again or visit Twitter Status for more information.