CloneMut有特质吗?

apt*_*002 5 clone rust borrow-checker

一个容易被忽视的特征clone()是它可以缩短隐藏在克隆值中的任何引用的生命周期.对于不可变引用来说,这通常是无用的,这是唯一Clone实现的引用.

然而,能够缩短隐藏在值内的可变引用的生命期是有用的.有什么像CloneMut特质?

我成功写了一个.我的问题是标准库中是否存在我应该使用的特性,即我是否重新发明轮子?

这个问题的其余部分包括细节和例子.

游乐场.

特例:该类型一个可变参考

作为一个热身,当您克隆的类型是一个可变引用时,以下内容就足够了,而不是以任何方式包装:

fn clone_mut<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
    *q
}
Run Code Online (Sandbox Code Playgroud)

请参阅此问题(调用它的位置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)
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例调用者:

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)
}
Run Code Online (Sandbox Code Playgroud)

请注意,除非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)
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,这不是在拉斯特(允许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)
    }
}
Run Code Online (Sandbox Code Playgroud)

Self和之间没有正式关系,这有点难看Self::To.例如,您可以编写clone_mut()该返回的实现77,完全忽略该Self类型.以下两个尝试表明为什么我认为相关类型是不可避免的.

尝试1

这编译:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,它与调用者不兼容,因为它没有两个不同的生命周期变量.

error[E0502]: cannot borrow `*p.0` as immutable because `p` is also borrowed as mutable
Run Code Online (Sandbox Code Playgroud)

错误消息中提到的不可变借位是println!()语句中的一个,而可变的借位是对它的调用clone_mut().特征限制了两个生命周期是相同的.

尝试2

这使用与尝试1相同的特征定义,但使用不同的实现:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

这甚至都没有编译.返回类型具有更长的生命周期,并且不能从具有更短生存期的参数生成.

将lifetime参数移动到方法声明上会产生相同的错误:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

与克隆的关系

顺便提一下,请注意CloneMut<'a, To=Self>严格要求Clone:

impl<'a, T: 'a> CloneMut<'a> for T where T: Clone {
    type To = Self;

    fn clone_mut(&'a mut self) -> Self {
        self.clone()
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我认为" CloneMut"是一个好名字的原因.

Kor*_*nel 1

引用的关键属性&mut是它们是唯一的他引用。

所以它并不是真正的克隆。你不能有两个独家参考。这是重新借用,因为只要“克隆”在范围内,源就完全无法使用。