Rust 不匹配的类型混淆编译器
Posted
技术标签:
【中文标题】Rust 不匹配的类型混淆编译器【英文标题】:Rust mismatched types confusing compiler 【发布时间】:2017-01-07 22:25:39 【问题描述】:我尝试使用 impl 来处理一些奇怪的类型逻辑。以下是该错误的快速重建:
trait Schrodingers
struct AliveCat;
impl Schrodingers for Container<AliveCat>
struct DeadCat;
impl Schrodingers for Container<DeadCat>
struct Container<Cat1>
where Container<Cat1>: Schrodingers
cat: Cat1,
impl<Cat2> Container<Cat2>
where Container<Cat2>: Schrodingers
fn dead_cat() -> Container<DeadCat>
let observed_cat = DeadCat;
Container cat: observed_cat
fn alive_cat() -> Container<AliveCat>
let observed_cat = AliveCat;
Container cat: observed_cat
fn main()
let dead_cat = Container::dead_cat();
let alive_cat = Container::alive_cat();
这会导致编译器错误:
error[E0308]: mismatched types
--> src/main.rs:19:26
|
19 | Container cat: observed_cat
| ^^^^^^^^^^^^ expected type parameter, found struct `DeadCat`
|
= note: expected type `Cat2`
= note: found type `DeadCat`
error[E0308]: mismatched types
--> src/main.rs:19:9
|
19 | Container cat: observed_cat
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `DeadCat`, found type parameter
|
= note: expected type `Container<DeadCat>`
= note: found type `Container<Cat2>`
error[E0308]: mismatched types
--> src/main.rs:24:26
|
24 | Container cat: observed_cat
| ^^^^^^^^^^^^ expected type parameter, found struct `AliveCat`
|
= note: expected type `Cat2`
= note: found type `AliveCat`
error[E0308]: mismatched types
--> src/main.rs:24:9
|
24 | Container cat: observed_cat
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `AliveCat`, found type parameter
|
= note: expected type `Container<AliveCat>`
= note: found type `Container<Cat2>`
我已经能够使用其他方法解决这个问题,但为什么编译器会觉得这很混乱?
【问题讨论】:
删除struct
本身上的where
子句使其工作,例如限定Container::<AliveCat>
在alive_cat()
。我认为struct
/impl
(两者都需要彼此)的循环性质意味着推理失败。
也可以完全摆脱Cat2
并在单独的impl
块中实现Container<DeadCat>
和Container<AliveCat>
。但事实上,失败的推论令人惊讶。
谢谢!我不知道你提到的限定语法与结构声明一起使用,这解决了这个问题。
【参考方案1】:
可以说,编译器是“靠墙”的。
结构体Container<Cat>
必须在结构体声明中直接实现Schrodingers
。
struct Container<Cat>
where Container<Cat>: Schrodingers
Container<C>
的 impl 块以相同的 trait bound 跟随它。
最后,我们有关联的函数,例如alive_cat
,它存在于Container<Cat>
中的每个Cat
,其中Container<Cat>: Schrodingers
,但忽略类型参数Cat
,返回一个Container<AliveCat>
。
然后编译器似乎错误地将参数类型Cat
推断为特定的AliveCat
,尽管在该impl
块中每个Cat
总是AliveCat
不一定是真的,导致奇怪的不一致和误导性的错误信息。就编译器的功能而言,这可能与对 Rustc 的一些调整一起工作,但不一定会发生。
幸运的是,有一些简单的开发指南可以防止此问题发生:
仅在绝对必要时对结构使用特征边界。大多数情况下,这些特征界限可以添加到适用的impl
子句中。否则,结构中的任何边界都必须应用于所有后续的 impl 块,即使该边界与实现的项目并不特别相关。
将构造函数编写为返回Self
的关联函数(或包含Self
的东西,例如Result<Self, _>
等)。这会迫使您为该构造函数编写一个独立的 impl
块,而不涉及泛型类型。
impl Container<DeadCat>
fn dead_cat() -> Self
let observed_cat = DeadCat;
Container cat: observed_cat
impl Container<AliveCat>
fn alive_cat() -> Self
let observed_cat = AliveCat;
Container cat: observed_cat
【讨论】:
以上是关于Rust 不匹配的类型混淆编译器的主要内容,如果未能解决你的问题,请参考以下文章
匹配Rust中的Option静态字符串文字[duplicate]