我在标准库文档中运行了下面的示例,遇到了一个难题。
我发现BorrowMut
trait的一个实现是Vec
,我不明白它是如何工作的。例如,下面的代码表明No.1工作,为什么No.2不工作,泛型T
做什么?
use std::borrow::BorrowMut;
fn check<T: BorrowMut<[i32]>>(mut v: T) {
assert_eq!(&mut [1, 2, 3], v.borrow_mut()); // ! no.1 can call, Why?
}
fn main() {
let v = vec![1, 2, 3];
// v.borrow_mut(); // ! no.2 Can't call,Why?
check(v);
}
1条答案
按热度按时间xzabzqsa1#
rustc显示的完整错误很好地解释了这一点。并强调:
BorrowMut
可以在一个类型上实现多次。例如,BorrowMut<Foo>
和BorrowMut<Bar>
都可以为Vec<i32>
实现;在这些示例中,Foo
和Bar
取代了“*type parameterBorrowed
declared on the traitBorrowMut
*",如its documentation所示(单击“Show declaration”)。在“no.1”中,您已指定
T: BorrowMut<[i32]>
;由于没有提到T
的BorrowMut
的其他实现,因此“type parameterBorrowed
declared on the traitBorrowMut
”可以明确地推断为[i32]
。在“no.2”中,对于您所追求的
BorrowMut
的实现存在模糊性:即使现在没有其他Vec<i32>
的BorrowMut
实现在作用域中,它们也可能潜伏在编译器不知道的地方(等待通过use
语句被带入作用域);即使现在没有其他的库,将来上游的crate(即std
库)也可以添加一个,这将破坏您的代码。因此,编译器会要求你明确地告诉它你所追求的是哪个实现,从而消除歧义。它通过报告“type annotations needed"来做到这一点,甚至向您展示了如何做到这一点:“ 使用潜在候选人的完全限定路径:<Vec<T> as BorrowMut<[T]>>::borrow_mut(v)
"。我们可以在这里这样做:但是,这不会起作用,因为另一个原因:Rust只在使用
.
方法语法调用时执行deref强制-当这样调用时,您必须显式传递&mut v
而不是v
(我已经提交了an issue关于这个错误的建议);但这在您的情况下仍然不起作用,因为v
没有声明为可变的。编译器还得出结论:
这样做会显示这些额外的信息,这可能也有帮助。
请建议错误消息如何更清楚地解释问题。
实际上,编译器上面的建议比解决这种情况下的二义性所需的更详细。您也可以通过以下两种方式解决它,而不提及
v
的类型:还要注意的是,对于
Vec
,您可以通过其固有的as_mut_slice
方法、索引(通过其std::ops::IndexMut
的实现)或显式或隐式调用std::ops::DerefMut::deref_mut
(即,使用解引用操作符)。分别为:事实上,由于解引用,
&mut Vec
也在强制站点(如函数参数和let
绑定)将coerces转换为可变切片-因此您通常可以只使用&mut v
,Rust将为您完成其余工作。See all approaches discussed in this answer on the Rust Playground。
考虑到它们都编译成完全相同的代码,你使用哪一个实际上只是一个偏好问题。但是,为了保持代码尽可能的清晰(因此也是维护),我建议索引方法
&mut v[..]
最清楚和简洁地表明您正在对整个向量进行可变切片。