diff --git a/examples/generics_with_trait_bounds.rs b/examples/trait_bounds.rs similarity index 58% rename from examples/generics_with_trait_bounds.rs rename to examples/trait_bounds.rs index fd327100d9ab9bca9686c8d120750d0cc8fec2a2..099e39a7db57cfd9d455dab7cf840608b9eb92a6 100644 --- a/examples/generics_with_trait_bounds.rs +++ b/examples/trait_bounds.rs @@ -1,13 +1,13 @@ // a struct with generics // a trait for double +// a function with trait bound use std::fmt::Debug; #[derive(Debug)] struct P<T> { x: T, - y: -pub trait Iterator<T> {T, + y: T, } trait Double { @@ -21,13 +21,15 @@ impl Double for P<u32> { } } -impl Double for P<u64> { +impl Double for String { fn double(&mut self) { - self.x += self.x; - self.y += self.y; + let s = self.clone(); + self.push_str(&s); } } +// This is a generic function over types +// implementing Double. fn quad<T>(x: &mut T) where T: Double, @@ -41,19 +43,18 @@ fn main() { quad(&mut p1); println!("{:?}", p1); - let mut p2 = P { x: 1u64, y: 2 }; - quad(&mut p2); - println!("{:?}", p2); + let mut s = "String, ".to_string(); + quad(&mut s); + println!("{:?}", s); } -// The types of p1 and p2 is known at compile time -// (See that rust analyses derives the types) +// Types of p1 and s are known at compile time // -// The compiler will "specialize" the call -// to double (as cheap as an ordinary call) +// The compiler will "specialize" the calls +// to double (as cheap as an ordinary calls) // // The quad function takes a generic parameter T -// the T : Double, is "trait bound" +// the T : Double, is a "trait bound" // meaning T is generic but must implement T // // As the the type at the call site is known @@ -63,7 +64,4 @@ fn main() { // The implementation is as efficient as an // as if written as ordinary functions. // -// Specialization is also called "monomorphization". -// Also C++ does this (but through templates). -// -// Zero-cost abstractions is the key to efficiency. +// We have zero-cost abstractions. diff --git a/examples/trait_objects.rs b/examples/trait_objects.rs index d7c1d87f6eb9775976c34891b6752a37bd91ea62..8d5d9e9d8c9642dae05740c113498a8e76d65813 100644 --- a/examples/trait_objects.rs +++ b/examples/trait_objects.rs @@ -9,6 +9,11 @@ struct P<T> { y: T, } +// Debug is a super trait of Double +// I.e, all types implementing Double must also implement +// Debug, and as a consequence: +// All types implementing Double is ensured to implement +// Debug. trait Double: Debug { fn double(&mut self); } @@ -20,13 +25,6 @@ impl Double for P<u32> { } } -impl Double for P<u64> { - fn double(&mut self) { - self.x += self.x; - self.y += self.y; - } -} - impl Double for String { fn double(&mut self) { let s = self.clone(); @@ -34,21 +32,11 @@ impl Double for String { } } -fn quad<T>(x: &mut T) -where - T: Double, -{ - x.double(); - x.double(); -} - fn main() { let mut p1 = P { x: 1u32, y: 2 }; - quad(&mut p1); println!("{:?}", p1); - let mut s = "String".to_string(); - quad(&mut s); + let mut s = "String, ".to_string(); println!("{:?}", s); let mut v: Vec<&mut dyn Double> = Vec::new(); @@ -59,7 +47,7 @@ fn main() { e.double(); // Here `e` implements Double // However we don't know at compile time - // which implementation (u32, u64 or String) + // which implementation (u32 or String) // so the compiler will generate // a dynamic dispatch. // @@ -78,7 +66,7 @@ fn main() { // Since debug is a Super trait of Double // The compiler knows that Debug is implemented // for each type that implement Double - // (P<u32>, P<u64> and String) + // (P<u32> and String) // // However it does not know at compile time // the concrete type of the vector elements, @@ -88,6 +76,7 @@ fn main() { // Notice, the overhead of dynamic dispatch is // merely a pointer indirection, so not a big deal right? // +// Hmmm, not really.... // The performance kill is likely NOT the additional pointer read // but rather that other optimizations are not possible. // diff --git a/examples/traits.rs b/examples/traits.rs index beac5d8e532124fab7104cab6e339224cf169a1f..399d6582881f687623174f227f4e18fec34b7373 100644 --- a/examples/traits.rs +++ b/examples/traits.rs @@ -39,8 +39,9 @@ fn main() { println!("{:?}", s); } -// Types of p1 and s is known at compile time -// Even if we now use Traits the compiler can -// specialize the calls to double. +// Types of p1 and s are known at compile time // -// We have a zero-cost abstraction. +// The compiler will "specialize" the calls +// to double (as cheap as an ordinary calls) +// +// We have zero-cost abstractions.