如果将返回值分配给变量之前,方法返回dyn将无法编译
在编写工厂方法数小时挣扎后,该方法返回包含通用类型字段(实现特征)的结构的实例,我发现它仅在返回变量之前将结果分配给变量时才进行编译并运行(有关完整的工作示例,请参见帖子的底部:
此编译和运行:
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 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
},
}
}
di dio_not_compile()
函数会导致以下错误:
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>`
这使我完全陷入困境。对我来说,两者之间没有语义差异,只有结果(暂时)存储在变量之前的事实。这里发生了什么?
完成示例(添加rand =“*”
到依赖项):
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();
}
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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里的区别是类型推理。在第一个示例中,因为表达式是返回值,因此编译器查看函数签名以确定
parent
的通用参数,它决定为dyn> dyn dyn isachild
。在第二个示例中,编译器需要推断变量parent
的类型。它首先查看分配给表达式的类型,然后parent {child:box :: box :: new(daughter {})}
的类型是明确的parent&lt; apent&lt; daight&gt; ,因此给出了该类型的变量,而不是
parent&lt; dyn isachild&gt;
。您可以通过明确地说编译器仅将box
的内容胁迫的内容来修复第二个示例,如果需要的话,将其固定在未介绍的类型上,因此这就是为什么需要明确具有变量的示例的原因。
The difference here is type inference. In the first example because the expression is the return value, the compiler looks to the function signature to determine the generic parameter of
Parent
, which it decides isdyn IsAChild
. In the second example, the compiler needs to infer the type of the variableparent
. It first looks at the type of the expression it is assigned to, and the type ofParent { child: Box::new(Daughter {}) }
is unambiguouslyParent<Daughter>
, so the variable is given that type instead ofParent<dyn IsAChild>
. You could fix th second example by explicitly sayingThe compiler only coerces the contents of the
Box
to an unsized type if it has to, so that's why the example with the variable needs to be explicit.这是因为编译器从我们对其的使用情况下推论了板条的确切类型。
当这是匹配语句的直接结果时,因此该功能的结果必须与
parent&lt; dyn isachild&gt;
完全匹配。但是,如果您将其存储在本地变量中,则该类型不受限制,它只是
parent&lt; daughter&gt;
或parent&lt; son&gt;
(no dyn the there)。当使用这些变量以产生函数的结果时,它们不匹配。
您可以强制变量
的类型让父级:parent&lt; dyn isachild&gt; = parent {child:box :: new(daughter {}),};
。It's because the compiler deduces the exact type of the crated
Parent
from the usage we make of it.When this is directly the result of the match statement, thus the result of the function, then this type must match exactly
Parent<dyn IsAChild>
.But if you store it in a local variable, the type is not constrained and it's simply
Parent<Daughter>
orParent<Son>
(no dyn here).When these variables are used in order to produce the result of the function, they do not match.
You can force the type of the variable
let parent: Parent<dyn IsAChild> = Parent { child: Box::new(Daughter {}), };
.