为何向方法传参时无法直接调用Rc::clone()?
为何向方法传参时无法直接调用Rc::clone()?
这问题我刚摸Rust的时候也踩过一模一样的坑!本质是Rust的类型推导和 trait 对象强制转换的时机问题,咱们掰开揉碎了说:
先看报错的核心原因
你写的struct2.add_child(Rc::clone(&struct1));之所以报错,是因为Rust没办法在函数参数的表达式位置,自动完成“从具体类型的Rc到trait对象的Rc”的深层转换:
struct1的类型是Rc<RefCell<Struct1>>,调用Rc::clone(&struct1)返回的类型和它完全一致,也是Rc<RefCell<Struct1>>。- 而
add_child需要的参数类型是Rc<RefCell<dyn Trait1>>,这里的差异在Rc内部的RefCell包裹的类型:一个是具体的Struct1,一个是 trait 对象dyn Trait1。 - 编译器在处理参数传递时,会先确定
Rc::clone的返回类型,再检查是否匹配参数类型。但它没办法在这一步自动把Rc<RefCell<Struct1>>直接转成Rc<RefCell<dyn Trait1>>——因为这种转换需要“穿透”Rc的包装,把内部的具体类型升级为trait对象,这个操作不能在函数调用的参数表达式里自动触发。
那单独赋值为什么就行?
当你写let clone = Rc::clone(&struct1);再把clone传给add_child时,情况就不一样了:
- 编译器看到
clone接下来要被传给需要Rc<RefCell<dyn Trait1>>的方法,它会自动触发强制类型转换:把Rc<RefCell<Struct1>>转换为Rc<RefCell<dyn Trait1>>。 - 这种转换是Rust允许的(因为
Struct1实现了Trait1),而且变量赋值的场景给了编译器足够的上下文,让它知道需要做这个向上转换。
还有个更直接的解决办法
其实不用单独写一行赋值,你也可以在参数位置显式指定类型转换,帮编译器“指明方向”:
struct2.add_child(Rc::clone(&struct1) as Rc<RefCell<dyn Trait1>>);
这样编译器就会先完成类型转换,再把结果传给add_child,也能正常编译。
最后再总结一下
- 单独赋值时,编译器能根据后续的使用上下文,自动完成具体类型到trait对象的Rc转换。
- 直接在参数里调用
Rc::clone时,编译器先推导返回类型为原具体类型,再发现和参数类型不匹配,又无法自动完成深层转换,所以就报错了。
备注:内容来源于stack exchange,提问作者eftshift0
相关产品推荐
相关产品推荐

