Default Parameters
Goal of This Episode
Learn where type parameters and const generic parameters can have defaults, and how to define them.
Concept
Default Type Parameters
On declarations for structs, enums, unions, type aliases, and traits, a type parameter that is almost always the same type can have a default. When that argument is omitted while using the type or trait, the default applies. Generic parameters on functions and methods cannot have defaults.
Take the standard library’s PartialEq as an example:
trait PartialEq<Rhs = Self> {
fn eq(&self, other: &Rhs) -> bool;
}
fn main() {}
Rhs = Self means: if you don’t specify Rhs, it defaults to Self. So impl PartialEq for Point is the same as impl PartialEq<Point> for Point — by default, you compare against your own type.
If you occasionally want to compare against a different type, just override it:
struct Point {
x: i32,
y: i32,
}
impl PartialEq<(i32, i32)> for Point {
fn eq(&self, other: &(i32, i32)) -> bool {
self.x == other.0 && self.y == other.1
}
}
fn main() {}
Defining Your Own
Use = in the generic definition to give a default:
struct Container<T = String> {
value: T,
}
fn main() {
let c: Container = Container { value: String::from("hello") }; // T defaults to String
let c2: Container<i32> = Container { value: 42 }; // specified manually
}
Defaults for const generics
const generic parameters can also have defaults on the same kinds of type and trait declarations. They cannot have defaults on functions or methods either.
struct Buffer<const N: usize = 1024> {
data: [u8; N],
}
fn main() {
let buf: Buffer = Buffer { data: [0; 1024] }; // N defaults to 1024
let small: Buffer<64> = Buffer { data: [0; 64] }; // specified manually
}
Parameters with Defaults Must Come Last
struct Pair<T, U = T> { // OK: U has a default and comes after T
first: T,
second: U,
}
fn main() {}
Example Code
struct Pair<T, U = T> {
first: T,
second: U,
}
impl<T: std::fmt::Debug, U: std::fmt::Debug> Pair<T, U> {
fn show(&self) {
println!("({:?}, {:?})", self.first, self.second);
}
}
fn main() {
// U uses the default (= T = i32)
let p1: Pair<i32> = Pair { first: 1, second: 2 };
p1.show();
// specify U manually
let p2: Pair<i32, &str> = Pair { first: 42, second: "hello" };
p2.show();
}
Recap
- Type parameters can have defaults on
struct,enum,union, type alias, andtraitdeclarations. constgeneric parameters can have defaults in the same places.- Function and method generic parameters cannot have defaults.
- The syntax is
<T = String>,<Rhs = Self>, or<const N: usize = 1024>. - Leave it out and the default applies; specify it and it’s overridden.
PartialEq<Rhs = Self>is the standard library’s classic example.- Parameters with defaults must come after parameters without them.