From c860ab84e91be959b0439127e06af64c69bae844 Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Tue, 17 Sep 2019 22:59:46 -0500 Subject: [PATCH] Fix #90: Extend the traits chapter, add supertraits and Fully Qualified syntax --- src/SUMMARY.md | 2 ++ src/traits/disambiguating.md | 62 ++++++++++++++++++++++++++++++++++++ src/traits/supertraits.md | 43 +++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 src/traits/disambiguating.md create mode 100644 src/traits/supertraits.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index f496410d4a..cd6bbc7b4f 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -139,6 +139,8 @@ - [Iterators](trait/iter.md) - [`impl Trait`](trait/impl_trait.md) - [Clone](trait/clone.md) + - [Supertraits](traits/supertraits.md) + - [Disambiguating overlapping traits](traits/disambiguating.md) - [macro_rules!](macros.md) - [Syntax](macros/syntax.md) diff --git a/src/traits/disambiguating.md b/src/traits/disambiguating.md new file mode 100644 index 0000000000..c893e9dc8d --- /dev/null +++ b/src/traits/disambiguating.md @@ -0,0 +1,62 @@ +# Disambiguating overlapping traits + +A type can implement many different traits. What if two traits both require the same name? For example, many traits might have a method named `get()`. They might even have different return types! + +Good news: because each trait implementation gets its own `impl` block, it's +clear which trait's `get` method you're implementing. + +What about when it comes time to _call_ those methods? To disambiguate between +them, we have to use Fully Qualified Syntax. + +```rust,editable +trait UsernameWidget { + // Get the selected username out of this widget + fn get(&self) -> String; +} + +trait AgeWidget { + // Get the selected age out of this widget + fn get(&self) -> u8; +} + +// A form with both a UsernameWidget and an AgeWidget +struct Form { + username: String, + age: u8, +} + +impl UsernameWidget for Form { + fn get(&self) -> String { + self.username.clone() + } +} + +impl AgeWidget for Form { + fn get(&self) -> u8 { + self.age + } +} + +fn main() { + let form = Form{ + username: "rustacean".to_owned(), + age: 28, + }; + + // If you uncomment this line, you'll get an error saying + // "multiple `get` found". Because, after all, there are multiple methods + // named `get`. + // println!("{}", form.get()); + + let username =
::get(&form); + assert_eq!("rustacean".to_owned(), username); + let age = ::get(&form); + assert_eq!(28, age); +} +``` + +### See also: + +[The Rust Programming Language chapter on Fully Qualified syntax][trpl_fqsyntax] + +[trpl_fqsyntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name diff --git a/src/traits/supertraits.md b/src/traits/supertraits.md new file mode 100644 index 0000000000..b28b8f4c9d --- /dev/null +++ b/src/traits/supertraits.md @@ -0,0 +1,43 @@ +# Supertraits + +Rust doesn't have "inheritance", but you can define a trait as being a superset +of another trait. For example: + +```rust,editable +trait Person { + fn name(&self) -> String; +} + +// Student is a supertrait of Person. +// Implementing Student requires you to also impl Person. +trait Student: Person { + fn university(&self) -> String; +} + +trait Programmer { + fn fav_language(&self) -> String; +} + +// CompSciStudent (computer science student) is a supertrait of both Programmer +// and Student. Implementing CompSciStudent requires you to impl both subtraits. +trait CompSciStudent: Programmer + Student { + fn git_username(&self) -> String; +} + +fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String { + format!( + "My name is {} and I attend {}. My Git username is {}", + student.name(), + student.university(), + student.git_username() + ) +} + +fn main() {} +``` + +### See also: + +[The Rust Programming Language chapter on supertraits][trpl_supertraits] + +[trpl_supertraits]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-supertraits-to-require-one-traits-functionality-within-another-trait