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类型.以下两个尝试表明为什么我认为相关类型是不可避免的.
这编译:
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().特征限制了两个生命周期是相同的.
这使用与尝试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"是一个好名字的原因.