为什么对于简单的特征实现,我会收到“溢出评估需求”错误?

web*_*rc2 8 rust

我收到了error[E0275]: overflow evaluating the requirement这个简单的代码,但我不知道如何解决它。错误消息建议为特征添加递归限制属性;但是,当我添加该属性时,它会生成一条新的错误消息,并建议我将递归限制加倍,直到它太大以至于rustc溢出堆栈。关于此错误已经有很多其他问题,但它们似乎与我的情况不同。

struct Foo<T>(T);

impl<T> From<&'_ Foo<T>> for String
where
    for<'a> &'a T: Into<String>,
{
    fn from(s: &Foo<T>) -> String {
        (&s.0).into()
    }
}

fn main() {
    println!("{}", String::from(&Foo(String::new())));
}
Run Code Online (Sandbox Code Playgroud)
error[E0275]: overflow evaluating the requirement `String: From<&'a Foo<_>>`
  --> src/main.rs:13:20
   |
13 |     println!("{}", String::from(&Foo(String::new())));
   |                    ^^^^^^^^^^^^
   |
   = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`playground`)
   = note: required because of the requirements on the impl of `for<'a> Into<String>` for `&'a Foo<_>`
   = note: required because of the requirements on the impl of `From<&'a Foo<Foo<_>>>` for `String`
   = note: 126 redundant requirements hidden
   = note: required because of the requirements on the impl of `From<&Foo<Foo<Foo<...>>>>` for `String`
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 9

这是一个未解决的编译器问题。首次报告于 2016 年,编号为#37748:在具有可重现示例的引用上递归实现的特征溢出:

trait Foo {}
impl<'a> Foo for &'a usize {}
impl<'a, T> Foo for &'a Vec<T> where &'a T: Foo {}

fn foo<T>(_: T) where for<'a> &'a T: Foo {}

fn main() {
    foo(0);
}
Run Code Online (Sandbox Code Playgroud)

虽然错误消息的具体内容随着时间的推移而发生变化,但显然核心问题是相同的:

trait Foo {}
impl<'a> Foo for &'a usize {}
impl<'a, T> Foo for &'a Vec<T> where &'a T: Foo {}

fn foo<T>(_: T) where for<'a> &'a T: Foo {}

fn main() {
    foo(0);
}
Run Code Online (Sandbox Code Playgroud)

这种模式在其他问题中也可以看到:#77158 #78982 #65420 #60603 #49017 #48767 #39959(这些可能需要一些整合)。不幸的是,这些都没有提供解决方案或通用解决方法。唯一真正的建议是将通用实现转换为具体实现,这可能可行,也可能不可能:

impl From<&'_ Foo<String>> for String {
    fn from(s: &Foo<String>) -> String {
        (&s.0).into()
    }
}
Run Code Online (Sandbox Code Playgroud)

根据我天真的理解,特征求解器将首先确定在解析过程中可供选择的候选实现。即使使用递归定义,它也可以很好地找到具体和通用的候选者,但如果递归的类型包括生命周期,则似乎会遇到麻烦。我不会假装知道到底哪里出了问题,只是生命周期的处理方式不同。您可以在Rustc 开发指南中阅读有关特征求解器的更多信息。

我不清楚 Rust 团队对这个问题的看法。它可以作为专业化的边缘情况来解决,或者他们可能正在等待粉笔来处理它。但显然这不是一个优先事项。