Example demonstrating API trait problem.

This commit is contained in:
Bill Thiede 2020-07-14 19:20:00 -07:00
commit 86bd20d074
3 changed files with 64 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
Cargo.lock

9
Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "rusttraits"
version = "0.1.0"
authors = ["Bill Thiede <git@xinu.tv>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

53
src/lib.rs Normal file
View File

@ -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<A: API>(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:
//! <Concrete as API>
trait API {
fn change_state(&mut self);
fn reset(&mut self);
}
#[derive(Default)]
struct Concrete {
count: isize,
}
fn func<A: API>(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);
}
}