Optional Extras
A neat feature of the Option<T>
type in Rust is that it implements the From<T>
trait. This allows for ergonomic optional parameters:
fn print_int<T: Into<Option<u32>>>(stuff: T) {
match stuff.into() {
Some(value) => println!("{}", value),
None => println!("no value!"),
}
}
This function can be called with a standard Option
value like print_int(Some(100))
or print_int(None)
. The key is that the Into
conversion also allows you to call without wrapping values in Some
. See it in action in the playground.
In Rust a common pattern when creating complex objects is to use the Builder Pattern. This is useful where you want to begin with some default state and apply partial customisations to it. In many cases however it is a bit heavyweight. Take for example constructing a node for an expression tree. In this case we might already have the components of the tree up front. We want to support parts of the tree being missing. In this case we can create builder functions with Into<Option<T>>
arguments make this kind of construction a little more ergonomic:
#[derive(Debug)]
pub enum Expr {
Literal(Option<i64>),
Unary(Option<Op>, Option<Box<Expr>>),
Binary(Option<Box<Expr>>, Option<Op>, Option<Box<Expr>>),
}
pub fn binary<L, O, R>(lhs: L, op: O, rhs: R) -> Expr
where L: Into<Option<Expr>>,
O: Into<Option<Op>>,
R: Into<Option<Expr>>,
{
Expr::Binary(lhs.into().map(Box::new),
op.into(),
rhs.into().map(Box::new))
}
When we come to create a tree we don’t have to mess around with Some
values and manually Box
things:
let tree = syntax_builder::literal(100);
let tree = syntax_builder::unary(None, tree);
let tree = syntax_builder::binary(tree, Op::Plus, None);
Check this out on the playground.
Comments