After struggling for hours with writing a factory method which returns instances of a struct containing a field of a generic type (implementing a trait), I find that it compiles and runs only if I do not assign the result to a variable before returning it (see the bottom of the post for a complete working example):
This compiles and runs:
fn compiles() -> Parent<dyn IsAChild> {
return match rand::thread_rng().gen_bool(1.0/2.0) {
true => Parent { child: Box::new(Daughter{} ) },
false => Parent { child: Box::new(Son{} ) },
}
}
This does not compile:
fn does_not_compile() -> Parent<dyn IsAChild> {
return match rand::thread_rng().gen_bool(1.0/2.0) {
true => {
let parent = Parent { child: Box::new(Daughter {}) };
parent
},
false => {
let parent = Parent { child: Box::new(Son {}) };
parent
},
}
}
The does_not_compile()
function results in the following error:
error[E0308]: mismatched types
--> src\main.rs:39:13
|
39 | parent
| ^^^^^^ expected trait object `dyn IsAChild`, found struct `Daughter`
|
= note: expected struct `Parent<(dyn IsAChild + 'static)>`
found struct `Parent<Daughter>`
This has me completely stumped. To me there is no semantic difference between the two, only the fact that the result is (temporarily) stored in a variable before it is returned. What is going on here?
Complete example (add rand = "*"
to the dependencies):
use rand::Rng;
trait IsAChild {}
struct Parent<T: IsAChild + ?Sized> {
child: Box<T>
}
struct Son;
impl IsAChild for Son {}
struct Daughter;
impl IsAChild for Daughter {}
fn compiles() -> Parent<dyn IsAChild> {
return match rand::thread_rng().gen_bool(1.0/2.0) {
true => Parent { child: Box::new(Daughter{} ) },
false => Parent { child: Box::new(Son{} ) },
}
}
fn compiles_too() -> Parent<dyn IsAChild> {
return match rand::thread_rng().gen_bool(1.0/2.0) {
true => {
println!("It's a girl!");
Parent { child: Box::new(Daughter{} ) }
},
false => {
println!("It's a boy!");
Parent { child: Box::new(Son{} ) }
},
}
}
/*
fn does_not_compile() -> Parent<dyn IsAChild> {
return match rand::thread_rng().gen_bool(1.0/2.0) {
true => {
let parent = Parent { child: Box::new(Daughter {}) };
parent
},
false => {
let parent = Parent { child: Box::new(Son {}) };
parent
},
}
}
*/
fn main() {
compiles();
}