我一直在试验,impl Trait在构建递归函数时遇到了这个错误:
error[E0308]: if and else have incompatible types
  --> src/main.rs:16:5
   |
16 | /     if logic {
17 | |         one(false)
18 | |     } else {
19 | |         two()
20 | |     }
   | |_____^ expected opaque type, found a different opaque type
   |
   = note: expected type `impl Meow` (opaque type)
              found type `impl Meow` (opaque type)
Run Code Online (Sandbox Code Playgroud)
这是重现的代码(Rust playground链接):
trait Meow {
    fn meow();
}
struct Cat(u64);
impl Meow for Cat {
    fn meow() {}
}
fn one(gate: bool) -> impl Meow {
    if gate {
        one(false)
    } else {
        two()
    }
}
fn two() -> impl Meow {
    Cat(42)
}
fn main() {
    let _ = one(true);
}
Run Code Online (Sandbox Code Playgroud)
我无法找到有关此特定问题的文档,我发现奇怪的是编译器返回的错误大致上说"这两个相同的东西是不同的".
有没有办法impl Trait在进行这种反复时支持语法,拜托?
我认为理想的编译器会接受您的代码,但当前的语言不允许\xe2\x80\x99 不允许递归推理,而在这种情况下,需要递归推理来弄清楚类型实际上是相同的。impl Meow您可以通过使用类型变量抽象类型来解决这个缺失的功能:
fn one_template<T: Meow>(gate: bool, two: impl FnOnce() -> T) -> T {\n    if gate {\n        one_template(false, two)\n    } else {\n        two()\n    }\n}\n\nfn one(gate: bool) -> impl Meow {\n    one_template(gate, two)\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n
        免责声明:这个答案假设读者理解-> impl Trait需要退回一种类型; 看到这个问题返回不同的类型.
Rust的核心原则之一是类型检查完全由函数,类型等接口驱动......并且实现被忽略.
关于-> impl Trait功能性,这通过语言将每个语言-> impl Trait视为不透明类型来表现,仅由其来自的功能来识别.
因此,您可以两次调用相同的函数:
use std::fmt::Debug;
fn cat(name: &str) -> impl Debug { format!("Meow {}", name) }
fn meow(g: bool) -> impl Debug {
    if g {
        cat("Mario")
    } else {
        cat("Luigi")
    }
}
fn main() {
    println!("{:?}", meow(true));
}
Run Code Online (Sandbox Code Playgroud)
但是你不能调用不同的函数,即使它们返回相同的类型,如果至少隐藏了一个函数-> impl Trait:
use std::fmt::Debug;
fn mario() -> impl Debug { "Meow Mario" }
fn luigi() -> &'static str { "Meow Luigi" }
fn meow(g: bool) -> impl Debug {
    if g {
        mario()
    } else {
        luigi()
    }
}
fn main() {
    println!("{:?}", meow(true));
}
Run Code Online (Sandbox Code Playgroud)
产量:
Run Code Online (Sandbox Code Playgroud)error[E0308]: if and else have incompatible types --> src/main.rs:8:9 | 8 | / if g { 9 | | mario() 10 | | } else { 11 | | luigi() 12 | | } | |_________^ expected opaque type, found &str | = note: expected type `impl std::fmt::Debug` found type `&str`
并隐藏着两个背后-> impl Trait:
use std::fmt::Debug;
fn mario() -> impl Debug { "Meow Mario" }
fn luigi() -> impl Debug { "Meow Luigi" }
fn meow(g: bool) -> impl Debug {
    if g {
        mario()
    } else {
        luigi()
    }
}
fn main() {
    println!("{:?}", meow(true));
}
Run Code Online (Sandbox Code Playgroud)
产生与您相同的错误消息:
Run Code Online (Sandbox Code Playgroud)error[E0308]: if and else have incompatible types --> src/main.rs:8:5 | 8 | / if g { 9 | | mario() 10 | | } else { 11 | | luigi() 12 | | } | |_____^ expected opaque type, found a different opaque type | = note: expected type `impl std::fmt::Debug` (opaque type) found type `impl std::fmt::Debug` (opaque type)
没有.
这里的语言不是特殊情况的递归,因此没有意识到,在问题中提出的情况下,只涉及一种类型.相反,它注意到fn one(...) -> impl Meow并fn two(...) -> impl Meow得出结论,那些是不同的不透明类型,因此编译时统一是不可能的.
提交RFC以调整这方面可能是合理的,可以通过争论递归的观点,也可以通过争论模块级可见性的观点来进行调整; 这超出了这个答案的范围.
唯一的可能性是确保类型是唯一的,这需要命名它.一旦您在名称中捕获了类型,就可以始终将其应用到需要匹配的任何位置.
我会把你推荐给@Anders的答案,因为他聪明的解决方法.