将 Rc<dyn Trait> 作为函数参数传递时出错

use*_*279 10 rust

将 aRc<dyn Trait>作为函数参数传递时,我面临一些奇怪的行为。下面的代码演示了这个问题。

use std::rc::Rc;

trait Trait {}

struct Struct {}

impl Trait for Struct {}

fn function(_t: Rc<dyn Trait>) {}

fn main() {
    let n = Rc::new(Struct {});

    // ok
    let r = Rc::clone(&n);
    function(r);

    // error, why?
    // function(Rc::clone(&n));
}
Run Code Online (Sandbox Code Playgroud)

如果我将 存储Rc在一个临时变量中,则一切正常。但是,如果我尝试Rc::clone在函数调用中直接调用,则会出现以下错误。

use std::rc::Rc;

trait Trait {}

struct Struct {}

impl Trait for Struct {}

fn function(_t: Rc<dyn Trait>) {}

fn main() {
    let n = Rc::new(Struct {});

    // ok
    let r = Rc::clone(&n);
    function(r);

    // error, why?
    // function(Rc::clone(&n));
}
Run Code Online (Sandbox Code Playgroud)

Struct实施Trait. 为什么我会收到这个错误?

tre*_*tcl 8

这基本上只是类型推断规则的一个皱纹。为了调用Rc::clone(&n),编译器必须知道 的类型参数Rc是什么。

let r = Rc::clone(&n);
function(r);
Run Code Online (Sandbox Code Playgroud)

在第一行,编译器看到它Rc::clone被一个类型为的参数调用&Rc<Struct>。它可以自由选择 for 的类型r,因此它推断被调用的函数应该是Rc::<Struct>::clone并且r也是Rc<Struct>。移动到下一行,调用function(r)只是强制 rRc<dyn Trait>.

function(Rc::clone(&n));
Run Code Online (Sandbox Code Playgroud)

这里编译器再次必须为 选择一个类型参数Rc,但它没有完全的自由:它必须选择可以传递给 的东西function。所以它假设类型参数是dyn Trait,因为这Rc<dyn Trait>function期望的。

但是,您不能调用Rc::<dyn Trait>::clone(&n),因为 whileRc<Struct>可以被强制为Rc<dyn Trait>强制不能通过引用传递(您不能将 a 强制&Rc<Struct>&Rc<dyn Trait>)。所以强制不能在Rc::clone(...)调用中发生。

您可以通过将类型参数指定为Struct使用 turbofish来编译单行版本:

function(Rc::<Struct>::clone(&n));
Run Code Online (Sandbox Code Playgroud)

或者通过function添加显式强制转换来暗示编译器它不应从其作为 的参数的位置推断类型:

function(Rc::clone(&n) as _);
Run Code Online (Sandbox Code Playgroud)

n.clone()也可以工作,因为for.方法解析过程对类型参数没有任何疑问:它总是会发现,Rc::<Struct>::clone因为自动取消引用只查看接收器类型( 的类型n)而不关心表达式的上下文。

有关的