I'm writing a function that does some processing on various data. I want to be able to take various action (for example, to have a dry run mode).
I was thinking about having a trait that takes the proper action once. Something like this:
trait DoStuff {
fn do_it(n: u32) -> u32;
}
struct DoItDry;
impl DoStuff for DoItDry {
fn do_it(n: u32) -> u32 {
println!("Got {}", n);
n
}
}
fn process(nums: &[u32], doer: &dyn DoStuff) {
for n in nums {
if *n > 1 && *n < 5 {
doer.do_it(*n);
}
}
}
However this fails because: error[E0038]: the trait
DoStuff cannot be made into an object
, with a few more details:
--> src\main.rs:2:8
|
1 | trait DoStuff {
| ------- this trait cannot be made into an object...
2 | fn do_it(n: u32) -> u32;// where Self: Sized;
| ^^^^^ ...because associated function `do_it` has no `self` parameter
help: consider turning `do_it` into a method by giving it a `&self` argument
|
2 | fn do_it(&self, n: u32) -> u32;// where Self: Sized;
| ^^^^^^
help: alternatively, consider constraining `do_it` so it does not apply to trait objects
|
2 | fn do_it(n: u32) -> u32 where Self: Sized;// where Self: Sized;
I don't really need a self
in this case, right? So I tried the second option:
trait DoStuff {
fn do_it(n: u32) -> u32 where Self: Sized;
}
struct DoItDry;
impl DoStuff for DoItDry {
fn do_it(n: u32) -> u32 where Self: Sized {
println!("Got {}", n);
n
}
}
fn process(nums: &[u32], doer: &dyn DoStuff) {
for n in nums {
if *n > 1 && *n < 5 {
doer.do_it(*n);
}
}
}
This still does not compile:
error[E0599]: no method named `do_it` found for reference `&dyn DoStuff` in the current scope
--> src\main.rs:17:18
|
17 | doer.do_it(*n);
| -----^^^^^----
| | |
| | this is an associated function, not a method
| help: disambiguate the associated function for the candidate: `DoStuff::do_it(&doer, *n)`
I don't really understand why this happens, so I tried the first suggestion:
trait DoStuff {
fn do_it(&self, n: u32) -> u32;
}
struct DoItDry;
impl DoStuff for DoItDry {
fn do_it(&self, n: u32) -> u32 {
println!("Got {}", n);
n
}
}
fn process(nums: &[u32], doer: &dyn DoStuff) {
for n in nums {
if *n > 1 && *n < 5 {
doer.do_it(*n);
}
}
}
fn main() {
let x: [u32; 3] = [1, 2, 3];
let d: DoItDry = DoItDry{};
process(&x, &d);
}
Now this works, but what if I want to actually have a new
function for the trait (which I do in my actual use case)? Like this:
trait DoStuff {
fn new() -> Self;
fn do_it(&self, n: u32) -> u32;
}
Now I'm back to square one. How can I do this?