导入std::borrow::Borrow后,Rc<RefCell<i32>>调用borrow触发Borrow::borrow而非RefCell::borrow的问题排查
嘿,这个坑我之前踩过!当你手动导入std::borrow::Borrow trait之后,调用current.borrow()时编译器会陷入方法匹配的歧义,优先去匹配trait Borrow的方法,反而忽略了我们真正想调用的RefCell自身的borrow方法,这就是报错的根源。
先看你给出的问题代码:
use std::borrow::Borrow; use std::rc::Rc; use std::cell::RefCell; fn next(current: Rc<RefCell<i32>>) { let m = (*current).borrow().abs(); //ok let l = current.borrow().abs(); //error }
为什么手动解包能正常工作?
当你写(*current)的时候,已经明确把Rc<RefCell<i32>>解引用成了RefCell<i32>类型,这时候调用的borrow()毫无疑问是RefCell自带的方法,它会返回Ref<i32>,自然能直接调用abs()方法。
为什么直接调用current.borrow()会报错?
因为你导入了Borrow trait,它的核心定义是这样的:
pub trait Borrow<Borrowed: ?Sized> { fn borrow(&self) -> &Borrowed; }
编译器看到current.borrow()时,会同时匹配两个可能的调用路径:
- 通过
Rc的 deref coercion 自动解引用到RefCell<i32>,调用RefCell::borrow - 直接调用
Borrowtrait的borrow方法
但Borrow的borrow方法是泛型的,编译器无法推断出你要借的Borrowed类型是什么,所以就抛出了“type annotations needed”的错误。
解决办法
给你几个实用的方案,按需选择:
方案一:明确调用
RefCell的方法
可以用完全限定语法,或者借助Rc的as_ref()方法来明确类型:// 方式1:完全限定调用 let l = RefCell::borrow(&*current).abs(); // 方式2:用as_ref()获取RefCell的引用 let l = current.as_ref().borrow().abs();两种写法都能让编译器明确,我们要调用的是
RefCell的borrow方法。方案二:移除
Borrow的导入
如果你代码里根本不需要用到std::borrow::Borrowtrait的功能,直接删掉use std::borrow::Borrow;这一行就好。此时编译器会自动通过 deref coercion 找到RefCell的borrow方法,current.borrow()就能正常运行了。方案三:手动标注类型(繁琐但可行)
如果你必须保留Borrow的导入,也可以手动指定解引用路径,不过写法比较啰嗦:let l = <Rc<RefCell<i32>> as std::ops::Deref>::deref(¤t).borrow().abs();
总结
核心问题就是导入Borrow trait后,方法调用出现了歧义,编译器无法确定你要调用哪个borrow。通过明确调用目标、移除不必要的导入这两种方式,都能轻松解决这个问题。
备注:内容来源于stack exchange,提问作者St.Antario

