更新到Rust 1.18打破了编译:E0034"clone_into"范围内的多个适用项目

Mat*_* M. 2 rust

我有这个简单的代码片段,它使用竞技场进行内存分配和一个特性,CloneInto其目的是将未知来源的结构克隆到a中Arena,调整生命周期:

struct Arena;

impl Arena {
    fn insert<'a, T: 'a>(&'a self, _: T) -> &'a mut T { unimplemented!() }
}

trait CloneInto<'a> {
    type Output: 'a;
    fn clone_into(&self, arena: &'a Arena) -> Self::Output;
}
Run Code Online (Sandbox Code Playgroud)

它可以按原样使用:

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
struct Simple<'a> { a: &'a usize }

impl<'a, 'target> CloneInto<'target> for Simple<'a> {
    type Output = Simple<'target>;

    fn clone_into(&self, arena: &'target Arena) -> Simple<'target> {
        Simple { a: arena.insert(*self.a) }
    }
}

fn main() {
    let arena = Arena;
    let _ = Simple { a: &1 }.clone_into(&arena);
}
Run Code Online (Sandbox Code Playgroud)

或者可以,直到更新到Rust 1.18.现在编译器发出以下错误:

error[E0034]: multiple applicable items in scope
  --> <anon>:25:30
   |
25 |     let _ = Simple { a: &1 }.clone_into(&arena);
   |                              ^^^^^^^^^^ multiple `clone_into` found
   |
note: candidate #1 is defined in an impl of the trait `CloneInto` for the type `Simple<'_>`
  --> <anon>:18:5
   |
18 | /     fn clone_into(&self, arena: &'target Arena) -> Simple<'target> {
19 | |         Simple { a: arena.insert(*self.a) }
20 | |     }
   | |_____^
   = note: candidate #2 is defined in an impl of the trait `std::borrow::ToOwned` for the type `_`
Run Code Online (Sandbox Code Playgroud)

即使我甚至没有导入stdToOwned!

Mat*_* M. 9

这是方法解析如何在Rust中工作的一个不幸的影响.与其他具有重载功能的语言不同,在Rust中,必须明确地解析要调用的确切函数,而不考虑其参数.

在这个特定的情况下,Rust 1.18带来了一个clone_intoToOwnedtrait 上调用的新的nightly方法,并且ToOwned无条件地为所有实现Clone和导入的类型(通过前奏)实现了特征.

这种方法不能在稳定状态下调用的事实没有影响; 该方法首先考虑用于解决,如果实际使用它将发出错误.

请注意,尽管有这种解决方法,但这种解决方法也有一些好处:人们常常不清楚当几个看起来可用时选择了过载,或者为什么没有选择预期的过载.通过明确性的错误,Rust使它成为一个明智的选择.

不幸的是,在这种情况下,这会导致Simple::clone_into()变得模棱两可.

没有办法选择退出ToOwned实现(并非没有放弃CloneCopy),因此必须切换到clone_into使用完全限定语法(FQS)的明确调用:

fn main() {
    let arena = Arena;
    let _ = CloneInto::clone_into(&Simple { a: &1 }, &arena);
}
Run Code Online (Sandbox Code Playgroud)