pub trait Folder<T, Acc> {
type Output;
type NextFolder;
// Required method
fn fold(self, acc: Acc, value: T) -> (Self::Output, Self::NextFolder);
}
Expand description
Define folders that fold an element of the tuple and specify another folder to be used to fold the next element of the tuple.
To fold a tuple with type Tuple<T0, T1, ... Tn>
, you need to construct a custom folder type,
which implements Folder<T0, Acc>
, and its NextFolder
implements Folder<T1, <F as Folder<T0, Acc>>::Output>
, and so on.
Pass your folder to tuple’s fold()
method, then the tuple will call
folder’s fold()
method and move its first element in, and then the tuple
move its second element in its NextFolder
’s fold()
method,
and so on.
NOTE: Folding a tuple will consume it. If this is not what you want, call as_ref()
or as_mut()
to create a new tuple that references its all members before folding.
§Quickly build a folder by macros
Here are two ways you can quickly build a folder.
§Fold tuples by element types
The folder!
macro helps you build a folder that folds tuples according to their element types.
For example:
use tuplez::{folder, tuple, TupleLike};
let tup = tuple!(Some(1), "2", Some(3.0));
let result = tup.fold(
folder! { String; // Type of `acc` of all closures must be the same and annotated at the front
|acc, x: &str| { acc + &x.to_string() }
<T: ToString> |acc, x: Option<T>| { acc + &x.unwrap().to_string() }
},
String::new(),
);
assert_eq!(result, "123".to_string());
§Fold tuples in order of their elements
You can create a new tuple with the same number of elements, whose elements are all callable objects that accepts the accumulation value
and an element and returns new accumulation value (FnOnce(Acc, T) -> Acc
), then, you can use that tuple as a folder.
For example:
use tuplez::{tuple, TupleLike};
let tup = tuple!(1, "2", 3.0);
let result = tup.fold(
tuple!(
|acc, x| (acc + x) as f64,
|acc: f64, x: &str| acc.to_string() + x,
|acc: String, x| acc.parse::<i32>().unwrap() + x as i32,
), // Type of `acc` of each closure is the return type of the previous closure.
0,
);
assert_eq!(result, 15);
§Custom folder
If you are not satisfied with the above three methods, you can customize a folder.
Here is an example, very simple but sufficient to show how to use:
use std::collections::VecDeque;
use tuplez::{fold::Folder, tuple, TupleLike};
struct MyFolder(VecDeque<i32>);
impl<T: std::fmt::Display> Folder<T, String> for MyFolder {
type Output = String;
type NextFolder = Self;
fn fold(mut self, acc: String, value: T) -> (Self::Output, Self::NextFolder) {
(
if self.0.len() == 1 {
acc + &format!("{}[{}]", value, self.0.pop_front().unwrap())
} else {
acc + &format!("{}[{}],", value, self.0.pop_front().unwrap())
},
self,
)
}
}
let tup = tuple!(3.14, "hello", 25);
let result = tup.fold(MyFolder(VecDeque::from(vec![1, 2, 3])), String::new());
assert_eq!(result, "3.14[1],hello[2],25[3]");
Required Associated Types§
sourcetype NextFolder
type NextFolder
Type of next folder to be use.
Required Methods§
sourcefn fold(self, acc: Acc, value: T) -> (Self::Output, Self::NextFolder)
fn fold(self, acc: Acc, value: T) -> (Self::Output, Self::NextFolder)
Fold a value, return the output value and next folder.