Reputation: 3598
I have code that is somewhat like
trait Checker {
fn check(&self, value: &str) -> bool;
}
struct ShortChecker {}
impl Checker for ShortChecker {
fn check(&self, value: &str) -> bool {
value.len() < 5
}
}
struct PrefixChecker {
prefix: String,
}
impl Checker for PrefixChecker {
fn check(&self, value: &str) -> bool {
value.starts_with(self.prefix)
}
}
fn check(value: &str, which: &str) -> bool {
let checker = if which == "short" {
ShortChecker { }
} else if which == "prefix" {
PrefixChecker { prefix: "xyzzy".to_string() }
} else {
panic!("Unknown option");
};
checker.check(value)
}
This fails to compile, since the different arms of the if statement return different types (ShortChecker
vs. PrefixChecker
). All I need is that there is local variable of type Checker
. My first attempt at fixing it was
let checker: Checker = ...
which gave a warning that traits without dyn
are deprecated. So I tried
let checker: dyn Checker = ...
That fails with E0308 because
= note: expected trait object `dyn Checker`
found struct `PrefixChecker`
If I was trying to store this in a struct to use later, I know I would need a Box<dyn Checker>
(or Rc
or ...). Do I also need something like that for a local variable? Since the variable is local, the compiler can reason about when it will go out of scope, so it seems that wrapping it could be unnecessary.
Is there a way to assign an object to a trait-typed local variable without wrapping it?
Upvotes: 1
Views: 774
Reputation: 70850
You can use Box
, but there's another neat trick you can use:
fn check(value: &str, which: &str) -> bool {
let (short_checker, prefix_checker);
let checker: &dyn Checker = if which == "short" {
short_checker = ShortChecker {};
&short_checker
} else if which == "prefix" {
prefix_checker = PrefixChecker {
prefix: "xyzzy".to_string(),
};
&prefix_checker
} else {
panic!("Unknown option");
};
checker.check(value)
}
Upvotes: 9