I wrote two structs that implement a common trait Solve
. Solve
has an associated type Answer
with trait bound Display
. I want the function create_solver
to return a trait object of Solve
.
I need help with writing the associate type Answer = ??
.
use std::fmt::Display;
fn main() {
let solver = create_solver(2);
let answer = solver.solve();
println!("{}", answer);
}
fn create_solver(kind: u32) -> Box<dyn Solve<Answer = ??>> {
match kind {
1 => Box::new(SolverOne),
2 => Box::new(SolverTwo),
_ => unreachable!()
}
}
trait Solve {
type Answer: Display;
fn solve(&self) -> Self::Answer;
}
struct SolverOne;
impl Solve for SolverOne {
type Answer = u32;
fn solve(&self) -> Self::Answer {
3
}
}
struct SolverTwo;
impl Solve for SolverTwo {
type Answer = String;
fn solve(&self) -> Self::Answer {
String::from("three")
}
}
I tried setting Answer = Box<dyn Display>
but that results in error.
fn create_solver(kind: u32) -> Box<dyn Solve<Answer = Box<dyn Display>>> {
match kind {
1 => Box::new(SolverOne),
2 => Box::new(SolverTwo),
_ => unreachable!()
}
}
trait Solve {
type Answer: Display;
fn solve(&self) -> Self::Answer;
}
struct SolverOne;
impl Solve for SolverOne {
type Answer = Box<u32>;
fn solve(&self) -> Self::Answer {
Box::new(3)
}
}
struct SolverTwo;
impl Solve for SolverTwo {
type Answer = Box<String>;
fn solve(&self) -> Self::Answer {
Box::new(String::from("three"))
}
}
Error message:
error[E0271]: type mismatch resolving `<SolverOne as Solve>::Answer == Box<(dyn Display + 'static)>`
--> src/main.rs:13:14
|
13 | 1 => Box::new(SolverOne),
| ^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<SolverOne as Solve>::Answer == Box<(dyn Display + 'static)>`
|
note: expected this to be `Box<(dyn std::fmt::Display + 'static)>`
--> src/main.rs:28:19
|
28 | type Answer = Box<u32>;
| ^^^^^^^^
= note: expected struct `Box<(dyn std::fmt::Display + 'static)>`
found struct `Box<u32>`
= note: required for the cast from `SolverOne` to the object type `dyn Solve<Answer = Box<(dyn std::fmt::Display + 'static)>>`
error[E0271]: type mismatch resolving `<SolverTwo as Solve>::Answer == Box<(dyn Display + 'static)>`
--> src/main.rs:12:5
|
12 | / match kind {
13 | | 1 => Box::new(SolverOne),
14 | | 2 => Box::new(SolverTwo),
15 | | _ => unreachable!()
16 | | }
| |_____^ type mismatch resolving `<SolverTwo as Solve>::Answer == Box<(dyn Display + 'static)>`
|
note: expected this to be `Box<(dyn std::fmt::Display + 'static)>`
--> src/main.rs:38:19
|
38 | type Answer = Box<String>;
| ^^^^^^^^^^^
= note: expected struct `Box<(dyn std::fmt::Display + 'static)>`
found struct `Box<String>`
= note: required for the cast from `SolverTwo` to the object type `dyn Solve<Answer = Box<(dyn std::fmt::Display + 'static)>>`
For more information about this error, try `rustc --explain E0271`
What should I set as Answer =
to make this work?
The associated type has to be the same for all types returned, and you have no such associated type. But you can create a wrapper type that using type erasure returns Box<dyn Display>
:
fn create_solver(kind: u32) -> Box<dyn Solve<Answer = Box<dyn Display>>> {
struct ErasedSolver<T>(T);
impl<T: Solve> Solve for ErasedSolver<T>
where
T::Answer: 'static,
{
type Answer = Box<dyn Display>;
fn solve(&self) -> Self::Answer {
Box::new(self.0.solve())
}
}
match kind {
1 => Box::new(ErasedSolver(SolverOne)),
2 => Box::new(ErasedSolver(SolverTwo)),
_ => unreachable!(),
}
}