Hi all,
I'm adding more traits to my text wrapping library, and I've run into a situation where my code works with one generic type parameter, but fails to compile with two parameters.
I've recreated the problem in this playground example.
The playground link has the full code, but in short, I have empty traits TraitA
and TraitB
, and I have structs OptionsA
and OptionsAB
:
struct OptionsA<A = Box<dyn TraitA>> {
a: A,
x: i32,
}
struct OptionsAB<A = Box<dyn TraitA>, B = Box<dyn TraitB>> {
a: A,
b: B,
x: i32,
}
The structs implement a builder pattern and lets you modify the a
and b
fields. So to set a
, the user would call this method:
impl<A> OptionsA<A> {
fn set_a<NewA>(self, new_a: NewA) -> OptionsA<NewA> {
OptionsA {
a: new_a,
x: self.x,
}
}
}
there are analog methods for OptionsAB
and for set_b
.
Now, my question is: I've noticed that I can use the struct with one generic parameters like this:
let cast_opt_a = OptionsA::new().set_a(Box::new(AAA) as Box<dyn TraitA>);
let defaults_opt_a: OptionsA = OptionsA::new().set_a(Box::new(AAA));
Both values are of type OptionsA<Box<dyn TraitA>>
.
When I try to do the same for my two-parameter struct, I get a compilation error:
let cast_opt_ab = OptionsAB::new()
.set_a(Box::new(AAA) as Box<dyn TraitA>)
.set_b(Box::new(BBB) as Box<dyn TraitB>);
let dynamic_opt_ab: OptionsAB = OptionsAB::new()
.set_a(Box::new(AAA))
.set_b(Box::new(BBB));
I find that the first line works and gives me a value of type OptionsAB<Box<dyn TraitA>, Box<dyn TraitB>>
with two trait objects. Howevr, the dynamic_opt_ab
line gives me a compilation error:
|
101 | let dynamic_opt_ab: OptionsAB = OptionsAB::new()
| _________________________---------___^
| | |
| | expected due to this
102 | | .set_a(Box::new(AAA))
103 | | .set_b(Box::new(BBB));
| |_____________________________^ expected trait object `dyn TraitA`, found struct `AAA`
|
= note: expected struct `OptionsAB<Box<(dyn TraitA + 'static)>, Box<(dyn TraitB + 'static)>>`
found struct `OptionsAB<Box<AAA>, Box<BBB>>`
Is there a nice way for me to let users customize the wrapping options in this way without having to specify the as Box<...>
for every trait?
One workaround that crossed my mind was to add extra methods for the Box<...>
case. However, I would prefer to avoid this if possible.
Thanks for any insights!