clone()
一个容易被忽视的特性是它可以缩短隐藏在克隆值中的任何引用的生命周期。对于不可变引用来说,这通常是无用的,这是Clone
实现的唯一类型。
但是,能够缩短隐藏在值中的可变引用的生命周期是有用的。有没有类似CloneMut
特征的东西?
我设法写了一个。我的问题是标准库中是否存在我应该使用的特性,即我是否重新发明轮子?
这个问题的其余部分包括细节和例子。
作为一种热身,当你克隆的类型是一个可变引用时,以下内容就足够了,而不是以任何方式包装:
fn clone_mut<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
有关示例调用方的信息,请参阅this question(称为reborrow()
)。
更有趣的情况是用户定义的类似于mutable-reference的类型。以下是如何编写特定于特定类型的clone_mut()
函数:
struct Foo<'a>(&'a mut f32);
impl<'b> Foo<'b> {
fn clone_mut<'a>(self: &'a mut Foo<'b>) -> Foo<'a> {
Foo(self.0)
}
}
以下是一个示例来电者:
fn main() {
let mut x: f32 = 3.142;
let mut p = Foo(&mut x);
{
let q = p.clone_mut();
*q.0 = 2.718;
}
println!("{:?}", *p.0)
}
请注意,除非q
的生命周期短于p
,否则不会编译。我想将其视为clone_mut()
的单元测试。
当尝试编写一个承认上述两种实现的特征时,问题起初就像是一种更高级的问题。例如,我想写这个:
trait CloneMut {
fn clone_mut<'a, 'b>(self: &'a mut Self<'b>) -> Self<'a>;
}
impl CloneMut for Foo {
fn clone_mut<'a, 'b>(self: &'a mut Self<'b>) -> Self<'a> {
Foo(self.0)
}
}
当然,Rust中不允许这样做(特别是Self<'a>
和Self<'b>
部分)。但是,问题可以解决。
以下代码编译(使用前面的Foo<'a>
定义)并与调用者兼容:
trait CloneMut<'a> {
type To: 'a;
fn clone_mut(&'a mut self) -> Self::To;
}
impl<'a, 'b> CloneMut<'a> for Foo<'b> {
type To = Foo<'a>;
fn clone_mut(&'a mut self) -> Self::To {
Foo(self.0)
}
}
Self
和Self::To
之间没有正式关系,这有点难看。例如,您可以编写一个返回clone_mut()
的{{1}}实现,完全忽略77
类型。以下两个尝试显示了为什么我认为相关类型是不可避免的。
编译:
Self
但是,它与调用者不兼容,因为它没有两个不同的生命周期变量。
trait CloneMut<'a> {
fn clone_mut(&'a mut self) -> Self;
}
impl<'a> CloneMut<'a> for Foo<'a> {
fn clone_mut(&'a mut self) -> Self {
Foo(self.0)
}
}
错误消息中提到的不可变借位是error[E0502]: cannot borrow `*p.0` as immutable because `p` is also borrowed as mutable
语句中的一个,而可变借位是对println!()
的调用。该特征将两个生命周期限制为相同。
这使用与尝试1相同的特征定义,但使用不同的实现:
clone_mut()
这甚至无法编译。返回类型具有更长的生命周期,并且不能从具有更短寿命的参数中生成。
将lifetime参数移到方法声明上会产生相同的错误:
trait CloneMut<'a> {
fn clone_mut(&'a mut self) -> Self;
}
impl<'a, 'b: 'a> CloneMut<'a> for Foo<'b> {
fn clone_mut(&'a mut self) -> Self {
Foo(self.0)
}
}
顺便提一下,请注意trait CloneMut {
fn clone_mut<'a>(&'a mut self) -> Self;
}
impl<'b> CloneMut for Foo<'b> {
fn clone_mut<'a>(&'a mut self) -> Self {
Foo(self.0)
}
}
严格强于CloneMut<'a, To=Self>
:
Clone
这就是为什么我认为&#34; impl<'a, T: 'a> CloneMut<'a> for T where T: Clone {
type To = Self;
fn clone_mut(&'a mut self) -> Self {
self.clone()
}
}
&#34;是一个好名字。
答案 0 :(得分:0)
&mut
引用的关键属性是它们是唯一的 exclusive 引用。
所以它不是一个真正的克隆。您不能有两个排他性引用。这是重新借用的,因为只要“ clone”在范围内,源就将完全不可用。