Pascal Hertleif
2018-09-05
Warning: Lots of code
Interrupt me when you have a question
(Please use the mic)
fn make_true(input: &str) -> String {
format!("{}!!", input)
}
struct Fact { text: String }
fn make_true(input: &Fact) -> Fact {
Fact { text: format!("{}!!", input.text) }
}
impl YourType {
}
make_true
as a methodstruct Fact { text: String }
impl Fact {
fn make_true(&self) -> Fact {
Fact { text: format!("{}!!", self.text) }
}
}
let fact = Fact { text: String::from("Lorem ipsum") };
let true_fact = fact.make_true();
Methods can operate on the data
Access the data using a form of self
as first parameter
self
”?You need to specify how you want self
:
&self
: Borrowed, read-only version&mut self
: Mutable, borrowed versionmut
] self
: Owned version, do whatever you want with it (incl. destroying it)make_true
struct Fact { text: String }
impl Fact {
fn make_true(&mut self) {
self.text.push_str("!!");
}
}
struct Fact { text: String }
impl Fact {
fn make_true(mut self) -> Fact {
self.text.push_str("!!");
self
}
}
trait Truth {
fn make_true(&self) -> Self
}
impl Truth for Fact {
fn make_true(&self) -> Self {
Fact { text: format!("{}!!", self.text) }
}
}
impl Truth for i32 {
fn make_true(&self) -> Self {
42
}
}
T: Truth
fn print_news<T: Truth>(facts: &[T]) {
for fact in facts {
let fact = fact.make_true();
println!("{}", fact);
}
}
Wait a second:
error[E0277]: `T` doesn't implement `std::fmt::Display`
--> src/lib.rs:16:20
|
16 | println!("{}", fact.make_true());
| ^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `T`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= help: consider adding a `where T: std::fmt::Display` bound
= note: required by `std::fmt::Display::fmt`
T
?Truth
use std::fmt;
fn print_news<T: Truth + fmt::Display>(facts: &[T]) {
for fact in facts {
let fact = fact.make_true();
println!("{}", fact);
}
}
But we’ll also need:
impl fmt::Display for Fact {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.text)
}
}
Here we go:
fn main() {
let facts = vec![
Fact { text: String::from("lorem ipsum") },
];
print_news(&facts);
}
$ cargo run
lorem ipsum!!
where
syntaxInstead of
fn print_news<T: Truth + fmt::Display>(facts: &[T]) {}
we can also write
fn print_news<T>(facts: &[T]) where T: Truth + fmt::Display {}
impl
simpl<T: Debug> Foo for Vec<T> {
// ...
}
That’s what we’ve been writing all this time
specify types you need to refer to that are specific to each impl
block
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
impl Iterator for FourIntegers {
type Item = i32;
fn next(&mut self) -> Option<i32> {}
}
trait SuperLog {
const LABEL: Display;
fn log(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
fact.make_true()
expands to
<Fact as Truth>::make_true(fact)
a + b
expands to std::ops::Add::add(a, b)
because of:
impl Add<i32> for i32 {
type Output = i32;
// ...
}
trait Fancy {}
impl Fancy for Vec<String> {}
I am Pascal
{twitter,github}.com/killercup
Slides: git.io/traits-from-the-ground-up