Like digest::Update::chain
.
trait VecChain<T> {
fn chain_push(self, value: T) -> Self;
fn chain_extend<I: IntoIterator<Item = T>>(self, iter: I) -> Self;
}
impl<T> VecChain<T> for Vec<T> {
fn chain_push(mut self, value: T) -> Self {
self.push(value);
self
}
fn chain_extend<I: IntoIterator<Item = T>>(mut self, iter: I) -> Self {
self.extend(iter);
self
}
}
#[derive(Clone, Copy, Debug)]
struct Item;
fn main() {
let v = Vec::new()
.chain_push(Item)
.chain_extend([Item; 3]);
dbg!(v);
}
playground
1 Like
The same concept for String
:
trait StringChain {
fn chain_push(self, ch: char) -> Self;
fn chain_push_str(self, string: &str) -> Self;
}
impl StringChain for String {
fn chain_push(mut self, ch: char) -> Self {
self.push(ch);
self
}
fn chain_push_str(mut self, string: &str) -> Self {
self.push_str(string);
self
}
}
fn main() {
let s = String::new()
.chain_push('a')
.chain_push_str("bcd");
dbg!(s);
}
playground
Vec::chain_append
for Vec::append
can also be considered.
That seems quite specific. Since it's already implementable with an extension trait or applied in a more general fashion with the tap
crate I don't see much benefit of having it in std.
7 Likes
This changes the API, but the goal is to have a nicer syntax. There are plenty of other types that could want fluent API too. This could be addressed more directly with a pipeline operator (|>
in some languages).
2 Likes