Tags: #rust #trait
// https://twitter.com/integralist/status/1508844091504836612
//
// Learning #rustlang and (yes it's a contrived example)
// I'm liking being able to piggy back off existing methods like .parse()
// and having it serialise data into a custom type via the FromStr trait.
//
// EXPLANATION:
// Roughly what is happening here is when we call parse() on the given
// string "beep" the compiler checks the type (in this case Foo is
// assigned to the variable f) and so it knows that Foo needs to
// implement the FromStr trait (which it sees that it does). So when the
// compiler then calls FromStr::from_self(self) (the self evaluating to
// the string "beep" and subsequently the correlating type Foo) it's able
// to swap out the traits from_self with the `impl std::str::FromStr for
// Foo` implementation.
//
// A similar example of this 'inference' of an implementation, and being
// able to call a trait method that has no default implementation, is:
//
// fn takes_vec(v: Vec<i32>) {}
// fn main() {
// takes_vec(FromIterator::from_iter(0..10));
// }
//
// Internally the range (0..10) is called with .collect() like so:
//
// (0..10).collect()
//
// Which means the compiler knows that the range must be collected into
// a Vect<i32>, and from there the compiler then knows to swap out the
// call to FromIterator::from_iter with the Vector's own implementation.
#[derive(Debug)]
struct Foo {
bar: String,
}
// http://doc.rust-lang.org/1.59.0/std/str/trait.FromStr.html
impl std::str::FromStr for Foo {
type Err = Box<dyn std::error::Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Foo{bar: s.to_string()})
}
}
fn main() {
let f = Foo{bar: "baz".to_string()};
println!("{:#?}", f);
println!("{:#?}", f.bar);
let f: Foo = "beep".parse().unwrap();
println!("{:#?}", f);
}