Tyrn
December 21, 2021, 8:19pm
#1
Hi,
I've got something like this:
pub trait Spinner {
fn new() -> Self;
fn message(&self, line: String);
fn stop(&mut self);
}
pub struct DaddySpinner {
spinner: Option<daddy::SpinnerHandle>,
}
impl Spinner for DaddySpinner { ... }
pub struct PrettySpinner {
spinner: Option<pretty::Spinner>,
}
impl Spinner for PrettySpinner { ... }
pub struct CuteSpinner {
spinner: Option<cute::SpinnerHandle>,
}
impl Spinner for CuteSpinner { ... }
Employed this way:
struct GlobalState {
pub spinner: spin::DaddySpinner,
...
}
fn main() {
let mut g = GlobalState {
spinner: spin::DaddySpinner::new(),
...
};
...
}
Whenever I want to change the spinner, I have to replace <...>Spinner
in two places. What's the best way to make the spinners naturally interchangeable?
kornel
December 21, 2021, 8:35pm
#2
You can use Box<dyn Spinner>
as a universal type that can hold any of the spinners. It can be changed even at run time.
Alternatively, you can parametrize GlobalState
by spinner:
struct GlobalState<S: Spinner> {
spinner: S,
}
Phlopsi
December 21, 2021, 8:47pm
#3
Spinner isn't object-safe, because of new
.
Declaring it as fn new() -> Self where Self: Sized
should do the trick. It won't be possible to call new
on a dyn Spinner
.
Tyrn
December 21, 2021, 8:48pm
#4
Somehow, I can't figure out what else do I have to do after
struct GlobalState<S: Spinner> {
spinner: S,
}
kpreid
December 21, 2021, 8:49pm
#5
If you just want to keep the required edit simpler and not change anything else, you can replace
spinner: spin::DaddySpinner::new(),
with
spinner: Spinner::new(),
and it will call the trait implementation's new()
for whichever concrete type is chosen. This will also work if you make GlobalState
generic.
system
closed
March 21, 2022, 8:50pm
#6
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.