` for any generic parameter `T` and
// caller `U`.
impl DoubleDrop for U {
// This method takes ownership of both passed arguments,
// deallocating both.
fn double_drop(self, _: T) {}
}
fn main() {
let empty = Empty;
let null = Null;
// Deallocate `empty` and `null`.
empty.double_drop(null);
//empty;
//null;
// ^ TODO: Try uncommenting these lines.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
See also:
Drop, struct, and trait
Bounds
When working with generics, the type parameters often must use traits as bounds to stipulate what functionality a type implements. For example, the following example uses the trait Display to print and so it requires T to be bound by Display; that is, T must implement Display.
// Define a function `printer` that takes a generic type `T` which
// must implement trait `Display`.
fn printer(t: T) {
println!("{}", t);
}
Bounding restricts the generic to types that conform to the bounds. That is:
struct S(T);
// Error! `Vec` does not implement `Display`. This
// specialization will fail.
let s = S(vec![1]);
Another effect of bounding is that generic instances are allowed to access the methods of traits specified in the bounds. For example:
// A trait which implements the print marker: `{:?}`.
use std::fmt::Debug;
trait HasArea {
fn area(&self) -> f64;
}
impl HasArea for Rectangle {
fn area(&self) -> f64 { self.length * self.height }
}
#[derive(Debug)]
struct Rectangle { length: f64, height: f64 }
#[allow(dead_code)]
struct Triangle { length: f64, height: f64 }
// The generic `T` must implement `Debug`. Regardless
// of the type, this will work properly.
fn print_debug(t: &T) {
println!("{:?}", t);
}
// `T` must implement `HasArea`. Any type which meets
// the bound can access `HasArea`'s function `area`.
fn area(t: &T) -> f64 { t.area() }
fn main() {
let rectangle = Rectangle { length: 3.0, height: 4.0 };
let _triangle = Triangle { length: 3.0, height: 4.0 };
print_debug(&rectangle);
println!("Area: {}", area(&rectangle));
//print_debug(&_triangle);
//println!("Area: {}", area(&_triangle));
// ^ TODO: Try uncommenting these.
// | Error: Does not implement either `Debug` or `HasArea`.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
As an additional note, where clauses can also be used to apply bounds in some cases to be more expressive.
See also:
std::fmt, structs, and traits
Testcase: empty bounds
A consequence of how bounds work is that even if a trait doesn't include any functionality, you can still use it as a bound. Eq and Copy are examples of such traits from the std library.
struct Cardinal;
struct BlueJay;
struct Turkey;
trait Red {}
trait Blue {}
impl Red for Cardinal {}
impl Blue for BlueJay {}
// These functions are only valid for types which implement these
// traits. The fact that the traits are empty is irrelevant.
fn red(_: &T) ->&'static str { "red" }
fn blue(_: &T) ->&'static str { "blue" }
fn main() {
let cardinal = Cardinal;
let blue_jay = BlueJay;
let _turkey = Turkey;
// `red()` won't work on a blue jay nor vice versa
// because of the bounds.
println!("A cardinal is {}", red(&cardinal));
println!("A blue jay is {}", blue(&blue_jay));
//println!("A turkey is {}", red(&_turkey));
// ^ TODO: Try uncommenting this line.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
See also:
std::cmp::Eq, std::marker::Copy, and traits
Multiple bounds
Multiple bounds can be applied with a +. Like normal, different types are separated with ,.
use std::fmt::{Debug, Display};
fn compare_prints(t: &T) {
println!("Debug: `{:?}`", t);
println!("Display: `{}`", t);
}
fn compare_types(t: &T, u: &U) {
println!("t: `{:?}`", t);
println!("u: `{:?}`", u);
}
fn main() {
let string = "words";
let array = [1, 2, 3];
let vec = vec![1, 2, 3];
compare_prints(&string);
//compare_prints(&array);
// TODO ^ Try uncommenting this.