diff --git a/deps/examples/associated_types.rs b/deps/examples/associated_types.rs new file mode 100644 index 00000000..c6c2cfaa --- /dev/null +++ b/deps/examples/associated_types.rs @@ -0,0 +1,15 @@ +trait Iterator { + type Item; // <-- associated type + // in Impl, use e.g. `Iterator` + + fn next(&mut self) -> Option; +} + +// Generic type with default +trait Add { + type Output; // <-- associated type + + fn add(self, rhs: Rhs) -> Self::Output; +} + +fn main() {} diff --git a/deps/examples/const_in_traits.rs b/deps/examples/const_in_traits.rs new file mode 100644 index 00000000..468764d6 --- /dev/null +++ b/deps/examples/const_in_traits.rs @@ -0,0 +1,13 @@ +trait Example { + const CONST_NO_DEFAULT: i32; + const CONST_WITH_DEFAULT: i32 = 99; +} +struct S; + +impl Example for S { + const CONST_NO_DEFAULT: i32 = 0; +} + +fn main() { + println!("{} {}", S::CONST_NO_DEFAULT, S::CONST_WITH_DEFAULT); +} diff --git a/deps/examples/generic_traits.rs b/deps/examples/generic_traits.rs new file mode 100644 index 00000000..8c345bd7 --- /dev/null +++ b/deps/examples/generic_traits.rs @@ -0,0 +1,17 @@ +trait Test { + fn test(_t: T); +} + +struct SomeStruct; + +impl Test for SomeStruct { + // note the <> in two places + fn test(_t: T) { + println!("test"); + } +} + +fn main() { + SomeStruct::test(1); + SomeStruct::test(true); +} diff --git a/deps/examples/newtype.rs b/deps/examples/newtype.rs new file mode 100644 index 00000000..e553a201 --- /dev/null +++ b/deps/examples/newtype.rs @@ -0,0 +1,17 @@ +use std::fmt; + +struct Wrapper(Vec); // tuple struct wrapping the type we want to add a non-local trait to. + +impl fmt::Display for Wrapper { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{}]", self.0.join(", ")) + } +} +// If we wanted the new type to have every method the inner type has, implement the `Deref` trait. + +fn main() { + println!( + "{}", + Wrapper(vec!["example".to_string(), "example 2".to_string()]) + ); +} diff --git a/deps/examples/rpit.rs b/deps/examples/rpit.rs new file mode 100644 index 00000000..74b92e29 --- /dev/null +++ b/deps/examples/rpit.rs @@ -0,0 +1,8 @@ +fn returns_closure() -> impl Fn(i32) -> i32 { + |x| x + 1 +} + +fn main() { + let f = returns_closure(); + println!("{}", f(1)); +} diff --git a/deps/examples/trait_bounds.rs b/deps/examples/trait_bounds.rs new file mode 100644 index 00000000..fb235cb7 --- /dev/null +++ b/deps/examples/trait_bounds.rs @@ -0,0 +1,31 @@ +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +// Trait bounds: the `print_hash` function is generic over an unknown type `T`, +// but requires that `T` implements the `Hash` trait. +fn print_hash(t: &T) { + let mut hasher = DefaultHasher::new(); + t.hash(&mut hasher); + println!("The hash is {:x}", hasher.finish()); +} +struct Pair { + first: A, + second: B, +} + +// Generics make it possible to implement a trait conditionally +// Here, the Pair type implements Hash if, and only if, its components do +impl Hash for Pair { + fn hash(&self, state: &mut H) { + self.first.hash(state); + self.second.hash(state); + } +} + +fn main() { + let p = Pair { + first: 1, + second: "2", + }; + print_hash(&p); +} diff --git a/deps/examples/traits.rs b/deps/examples/traits.rs new file mode 100644 index 00000000..1e07c0f1 --- /dev/null +++ b/deps/examples/traits.rs @@ -0,0 +1,27 @@ +pub trait Summary { + fn summarize(&self) -> String; +} + +pub struct NewsArticle { + pub headline: String, + pub location: String, + pub author: String, + pub content: String, +} + +// Implement Trait on a Type +impl Summary for NewsArticle { + fn summarize(&self) -> String { + format!("{}, by {} ({})", self.headline, self.author, self.location) + } +} + +fn main() { + let na = NewsArticle { + headline: "headline".to_string(), + location: "location".to_string(), + author: "author".to_string(), + content: "...".to_string(), + }; + println!("Summary: {}", na.summarize()); +} diff --git a/deps/examples/traits2.rs b/deps/examples/traits2.rs new file mode 100644 index 00000000..d6b92a86 --- /dev/null +++ b/deps/examples/traits2.rs @@ -0,0 +1,10 @@ +trait Summary { + fn summarize_author(&self) -> String; + + fn summarize(&self) -> String { + // <-- default implementation + format!("(Read more from {}...)", self.summarize_author()) // <-- can call a non-default method + } +} + +fn main() {} diff --git a/deps/examples/traits3.rs b/deps/examples/traits3.rs new file mode 100644 index 00000000..854628fc --- /dev/null +++ b/deps/examples/traits3.rs @@ -0,0 +1,14 @@ +use std::fmt; + +trait OutlinePrint: fmt::Display { + fn outline_print(&self) { + println!("* {} *", self); // can use println! because self is guaranteed to implement Display + } +} + +// String implements Display. That would not work otherwise. +impl OutlinePrint for String {} + +fn main() { + String::from("test").outline_print(); +} diff --git a/deps/examples/traits4.rs b/deps/examples/traits4.rs new file mode 100644 index 00000000..613a16ae --- /dev/null +++ b/deps/examples/traits4.rs @@ -0,0 +1,14 @@ +trait MyHash { + fn myhash(&self) -> u64; +} + +impl MyHash for i64 { + fn myhash(&self) -> u64 { + *self as u64 + } +} + +fn main() { + let x = 1i64; + println!("{}", x.myhash()); +} diff --git a/deps/examples/traits5.rs b/deps/examples/traits5.rs new file mode 100644 index 00000000..c980150e --- /dev/null +++ b/deps/examples/traits5.rs @@ -0,0 +1,25 @@ +#![allow(dead_code)] + +use std::clone::Clone; +use std::fmt::Debug; + +// Note the `+` +fn a_function(item: &(impl Debug + Clone)) { + println!("{:?}", item.clone()); +} + +fn some_function(_t: &T, _u: &U) -> i32 +where + T: Debug + Clone, // note the `+` + U: Debug + Clone, +{ + 42 +} + +#[derive(Debug, Clone)] +struct S; + +fn main() { + let s = S; + a_function(&s); +} diff --git a/deps/examples/traits_as_parameters.rs b/deps/examples/traits_as_parameters.rs new file mode 100644 index 00000000..5b847bc4 --- /dev/null +++ b/deps/examples/traits_as_parameters.rs @@ -0,0 +1,31 @@ +// Accepts any type that implements the specified trait: +fn notify(item: &impl Summary) { + println!("Breaking news! {}", item.summarize()); +} + +// Trait bound syntax (mostly equivalent): +fn notify2(item: &T) { + println!("Breaking news! {}", item.summarize()); +} + +trait Summary { + fn summarize(&self) -> String; +} + +struct Article { + txt: String, +} + +impl Summary for Article { + fn summarize(&self) -> String { + self.txt.clone() + } +} + +fn main() { + let a = Article { + txt: String::from("some text"), + }; + notify(&a); + notify2(&a); +} diff --git a/src/lang/traits.md b/src/lang/traits.md index d09e7b7f..a2028bd7 100644 --- a/src/lang/traits.md +++ b/src/lang/traits.md @@ -1,59 +1,21 @@ # Traits ```rust,editable -pub trait Summary { - fn summarize(&self) -> String; -} - -pub struct NewsArticle { - pub headline: String, - pub location: String, - pub author: String, - pub content: String, -} - -// Implement Trait on a Type -impl Summary for NewsArticle { - fn summarize(&self) -> String { - format!("{}, by {} ({})", self.headline, self.author, self.location) - } -} - -fn main() { - let na = NewsArticle { headline: "headline".to_string(), location: "location".to_string(), author: "author".to_string(), content: "...".to_string()}; - println!("Summary: {}", na.summarize()); -} +{{#include ../../deps/examples/traits.rs}} ``` Trait methods are in scope only when their trait is. ## Default implementation -```rust,editable,ignore -pub trait Summary { - fn summarize_author(&self) -> String; - - fn summarize(&self) -> String { // default implementation - format!("(Read more from {}...)", self.summarize_author()) // can call a non-default method - } -} +```rust,editable +{{#include ../../deps/examples/traits2.rs}} ``` ## Supertraits ```rust,editable -use std::fmt; - -trait OutlinePrint: fmt::Display { - fn outline_print(&self) { - println!("* {} *", self); // can use println! because self is guaranteed to implement Display - } -} - -// String implements Display. That would not work otherwise. -impl OutlinePrint for String {} - -fn main() { String::from("test").outline_print(); } +{{#include ../../deps/examples/traits3.rs}} ``` ## Newtype pattern @@ -61,204 +23,55 @@ fn main() { String::from("test").outline_print(); } Unlike interfaces in languages like Java, C# or Scala, new traits can be implemented for _existing_ types. ```rust,editable -trait MyHash { - fn myhash(&self) -> u64; -} - -impl MyHash for i64 { - fn myhash(&self) -> u64 { - *self as u64 - } -} - -fn main() { - let x = 1i64; - println!("{}", x.myhash()); -} +{{#include ../../deps/examples/traits4.rs}} ``` -One restriction to note is that we can implement a trait on a type only if at least one of the trait or the type is local to our crate. If neither are, use the Newtype pattern: +One restriction to note is that we can implement a trait on a type only if at least one of the trait or the type is local to our crate. If neither are, use the newtype pattern: ```rust,editable -use std::fmt; - -struct Wrapper(Vec); // tuple struct wrapping the type we want to add a non-local trait to. - -impl fmt::Display for Wrapper { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{}]", self.0.join(", ")) - } -} -// If we wanted the new type to have every method the inner type has, implement the `Deref` trait. - -fn main() { - println!("{}", Wrapper(vec!["example".to_string(), "example 2".to_string()])); -} +{{#include ../../deps/examples/newtype.rs}} ``` -## Trait as parameter +## Traits as parameters ```rust,editable -// Accepts any type that implements the specified trait: -fn notify(item: &impl Summary) { - println!("Breaking news! {}", item.summarize()); -} - -// Trait bound syntax (mostly equivalent): -fn notify2(item: &T) { - println!("Breaking news! {}", item.summarize()); -} - -pub trait Summary { - fn summarize(&self) -> String; -} - -struct Article { - txt: String, -} - -impl Summary for Article { - fn summarize(&self) -> String { - self.txt.clone() - } -} - -fn main() { - let a = Article { txt: String::from("some text") }; - notify(&a); - notify2(&a); -} +{{#include ../../deps/examples/traits_as_parameters.rs}} ``` ## Multiple traits ```rust,editable -#![allow(dead_code)] -use std::fmt::Debug; -use std::clone::Clone; - -// Note the `+` -fn a_function(item: &(impl Debug + Clone)) { - println!("{:?}", item.clone()); -} - -fn some_function(t: &T, u: &U) -> i32 -where - T: Debug + Clone, // note the `+` - U: Debug + Clone, -{ - 42 -} - -#[derive(Debug, Clone)] -struct S; - -fn main() { - let s = S; - a_function(&s); -} +{{#include ../../deps/examples/traits5.rs}} ``` ## Return-position impl Trait ```rust,editable -fn returns_closure() -> impl Fn(i32) -> i32 { - |x| x + 1 -} - -fn main() { - let f = returns_closure(); - println!("{}", f(1)); -} +{{#include ../../deps/examples/rpit.rs}} ``` ## Generic traits ```rust,editable -trait Test { - fn test(_t: T); -} - -struct SomeStruct; - -impl Test for SomeStruct { // note the <> in two places - fn test(_t: T) { - println!("test"); - } -} - -fn main() { - SomeStruct::test(1); - SomeStruct::test(true); -} +{{#include ../../deps/examples/generic_traits.rs}} ``` ## Associated types -```rust,editable,ignore -trait Iterator { - type Item; // in Impl, use e.g. `Iterator` - - fn next(&mut self) -> Option; -} -``` - -```rust,editable,ignore -trait Add { // default generic type - type Output; - - fn add(self, rhs: Rhs) -> Self::Output; -} +```rust,editable +{{#include ../../deps/examples/associated_types.rs}} ``` ## Trait bounds ```rust,editable -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; - -// Trait bounds: the `print_hash` function is generic over an unknown type `T`, -// but requires that `T` implements the `Hash` trait. -fn print_hash(t: &T) { - let mut hasher = DefaultHasher::new(); - t.hash(&mut hasher); - println!("The hash is {:x}", hasher.finish()); -} - -struct Pair { first: A, second: B } - -// Generics make it possible to implement a trait conditionally -// Here, the Pair type implements Hash if, and only if, its components do -impl Hash for Pair { - fn hash(&self, state: &mut H) { - self.first.hash(state); - self.second.hash(state); - } -} - -fn main() { - let p = Pair { first: 1, second: "2" }; - print_hash(&p); -} +{{#include ../../deps/examples/trait_bounds.rs}} ``` ## Constants in traits ```rust,editable -trait Example { - const CONST_NO_DEFAULT: i32; - const CONST_WITH_DEFAULT: i32 = 99; -} - -struct S; - -impl Example for S { - const CONST_NO_DEFAULT: i32 = 0; -} - -fn main() { - println!("{} {}", S::CONST_NO_DEFAULT, S::CONST_WITH_DEFAULT); -} +{{#include ../../deps/examples/const_in_traits.rs}} ``` ## Async and traits