commit 86bd20d07435707304fd04681779a6c9edfc9519 Author: Bill Thiede Date: Tue Jul 14 19:20:00 2020 -0700 Example demonstrating API trait problem. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..31a5ef7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rusttraits" +version = "0.1.0" +authors = ["Bill Thiede "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..77ede94 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,53 @@ +//! Illustrates problem with &mut trait implementations and non-&mut generic functions. +//! +//! error[E0277]: the trait bound `&mut Concrete: API` is not satisfied +//! --> src/lib.rs:32:14 +//! | +//! 24 | fn func(mut a: A) { +//! | --- required by this bound in `func` +//! ... +//! 32 | func(self); +//! | ^^^^ the trait `API` is not implemented for `&mut Concrete` +//! | +//! = help: the following implementations were found: +//! +trait API { + fn change_state(&mut self); + fn reset(&mut self); +} + +#[derive(Default)] +struct Concrete { + count: isize, +} + +fn func(mut a: A) { + a.reset(); +} + +impl API for Concrete { + // We don't want this function to be `self` because we don't want the method to consume the + // object. + fn change_state(&mut self) { + func(self); + } + // This mutates the state of `Concrete`, so it needs to be `&mut`, and will be called from + // `func`. + fn reset(&mut self) { + self.count = 0; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let mut c = Concrete::default(); + c.count = 1; + assert_eq!(c.count, 1); + c.change_state(); + assert_eq!(c.count, 0); + } +}