Skip to content
Snippets Groups Projects
Commit 38748e2b authored by Per Lindgren's avatar Per Lindgren
Browse files

examples

parent cfd6b987
No related branches found
No related tags found
No related merge requests found
// a struct with generics // a struct with generics
// a trait for double // a trait for double
// a function with trait bound
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Debug)] #[derive(Debug)]
struct P<T> { struct P<T> {
x: T, x: T,
y: y: T,
pub trait Iterator<T> {T,
} }
trait Double { trait Double {
...@@ -21,13 +21,15 @@ impl Double for P<u32> { ...@@ -21,13 +21,15 @@ impl Double for P<u32> {
} }
} }
impl Double for P<u64> { impl Double for String {
fn double(&mut self) { fn double(&mut self) {
self.x += self.x; let s = self.clone();
self.y += self.y; self.push_str(&s);
} }
} }
// This is a generic function over types
// implementing Double.
fn quad<T>(x: &mut T) fn quad<T>(x: &mut T)
where where
T: Double, T: Double,
...@@ -41,19 +43,18 @@ fn main() { ...@@ -41,19 +43,18 @@ fn main() {
quad(&mut p1); quad(&mut p1);
println!("{:?}", p1); println!("{:?}", p1);
let mut p2 = P { x: 1u64, y: 2 }; let mut s = "String, ".to_string();
quad(&mut p2); quad(&mut s);
println!("{:?}", p2); println!("{:?}", s);
} }
// The types of p1 and p2 is known at compile time // Types of p1 and s are known at compile time
// (See that rust analyses derives the types)
// //
// The compiler will "specialize" the call // The compiler will "specialize" the calls
// to double (as cheap as an ordinary call) // to double (as cheap as an ordinary calls)
// //
// The quad function takes a generic parameter T // 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 // meaning T is generic but must implement T
// //
// As the the type at the call site is known // As the the type at the call site is known
...@@ -63,7 +64,4 @@ fn main() { ...@@ -63,7 +64,4 @@ fn main() {
// The implementation is as efficient as an // The implementation is as efficient as an
// as if written as ordinary functions. // as if written as ordinary functions.
// //
// Specialization is also called "monomorphization". // We have zero-cost abstractions.
// Also C++ does this (but through templates).
//
// Zero-cost abstractions is the key to efficiency.
...@@ -9,6 +9,11 @@ struct P<T> { ...@@ -9,6 +9,11 @@ struct P<T> {
y: 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 { trait Double: Debug {
fn double(&mut self); fn double(&mut self);
} }
...@@ -20,13 +25,6 @@ impl Double for P<u32> { ...@@ -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 { impl Double for String {
fn double(&mut self) { fn double(&mut self) {
let s = self.clone(); let s = self.clone();
...@@ -34,21 +32,11 @@ impl Double for String { ...@@ -34,21 +32,11 @@ impl Double for String {
} }
} }
fn quad<T>(x: &mut T)
where
T: Double,
{
x.double();
x.double();
}
fn main() { fn main() {
let mut p1 = P { x: 1u32, y: 2 }; let mut p1 = P { x: 1u32, y: 2 };
quad(&mut p1);
println!("{:?}", p1); println!("{:?}", p1);
let mut s = "String".to_string(); let mut s = "String, ".to_string();
quad(&mut s);
println!("{:?}", s); println!("{:?}", s);
let mut v: Vec<&mut dyn Double> = Vec::new(); let mut v: Vec<&mut dyn Double> = Vec::new();
...@@ -59,7 +47,7 @@ fn main() { ...@@ -59,7 +47,7 @@ fn main() {
e.double(); e.double();
// Here `e` implements Double // Here `e` implements Double
// However we don't know at compile time // However we don't know at compile time
// which implementation (u32, u64 or String) // which implementation (u32 or String)
// so the compiler will generate // so the compiler will generate
// a dynamic dispatch. // a dynamic dispatch.
// //
...@@ -78,7 +66,7 @@ fn main() { ...@@ -78,7 +66,7 @@ fn main() {
// Since debug is a Super trait of Double // Since debug is a Super trait of Double
// The compiler knows that Debug is implemented // The compiler knows that Debug is implemented
// for each type that implement Double // for each type that implement Double
// (P<u32>, P<u64> and String) // (P<u32> and String)
// //
// However it does not know at compile time // However it does not know at compile time
// the concrete type of the vector elements, // the concrete type of the vector elements,
...@@ -88,6 +76,7 @@ fn main() { ...@@ -88,6 +76,7 @@ fn main() {
// Notice, the overhead of dynamic dispatch is // Notice, the overhead of dynamic dispatch is
// merely a pointer indirection, so not a big deal right? // merely a pointer indirection, so not a big deal right?
// //
// Hmmm, not really....
// The performance kill is likely NOT the additional pointer read // The performance kill is likely NOT the additional pointer read
// but rather that other optimizations are not possible. // but rather that other optimizations are not possible.
// //
......
...@@ -39,8 +39,9 @@ fn main() { ...@@ -39,8 +39,9 @@ fn main() {
println!("{:?}", s); println!("{:?}", s);
} }
// Types of p1 and s is known at compile time // Types of p1 and s are known at compile time
// Even if we now use Traits the compiler can
// specialize the calls to double.
// //
// 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.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment