clone()
的一个容易被忽视的特征是它可以缩短隐藏在被克隆值中的任何引用的生命周期。这对于不可变引用通常是无用的,这是唯一一种 Clone
已实现。
但是,能够缩短隐藏在值中的可变 引用的生命周期会很有用。有没有类似 CloneMut
的东西特质?
我写了一篇。我的问题是标准库中是否有我应该使用的特性,即我是在重新发明轮子吗?
这个问题的其余部分由详细信息和示例组成。
特殊情况:类型是一个可变引用
作为热身,当您克隆的类型是可变引用时,以下内容就足够了,没有以任何方式包装:
fn clone_mut<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
参见 this question (它被称为 reborrow()
)作为一个示例调用者。
特殊情况:引用类型虽然是用户定义的,但已知
一个更有趣的案例是用户定义的类似可变引用的类型。下面是如何写一个 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()
的实现。返回 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)
}
}
但是,它与调用者不兼容,因为它没有两个不同的生命周期变量。
error[E0502]: cannot borrow `*p.0` as immutable because `p` is also borrowed as mutable
错误消息中提到的不可变借用是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)
}
}
这甚至无法编译。返回类型具有较长的生命周期,并且不能由具有较短生命周期的参数生成。
将生命周期参数移到方法声明上会产生相同的错误:
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
:
impl<'a, T: 'a> CloneMut<'a> for T where T: Clone {
type To = Self;
fn clone_mut(&'a mut self) -> Self {
self.clone()
}
}
这就是为什么我认为“CloneMut
”是一个好名字。
最佳答案
&mut
引用的关键属性是它们是唯一的独占 引用。
所以它不是真正的克隆。您不能有两个排他性 引用。这是一个重新借用,因为只要“克隆”在范围内,源将完全无法使用。
关于rust - 有 CloneMut 特性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43038332/