有没有一种方法可以编写
my_function
,以便我可以传入实现 MyTrait
的任何值,然后能够将其传递到多个子函数调用中?
struct MyType1;
struct MyType2;
trait MyTrait<'a> {}
impl<'a> MyTrait<'a> for &MyType1 {}
impl<'a> MyTrait<'a> for &mut MyType2 {}
fn my_function<'a, T: 'a>(x: &'a T)
where
&'a T: MyTrait<'a>,
{
some_library_function(x);
some_library_function(x);
}
fn some_library_function<'a>(x: impl MyTrait<'a>) {}
fn main() {
let foo = MyType1;
let mut bar = MyType2;
my_function(&foo);
// expected `&MyType1`, found `&mut MyType2`
my_function(&mut bar);
}
我尝试过的一些事情及其结果:
如果
my_function
声明T: MyTrait
,我只能调用some_library_function
一次,因为x
已移动。
说
&'a T: MyTrait<'a>
允许我多次调用some_library_function
,但是my_function
只支持共享引用的实现,即&MyType1
,而不是可变引用,即我的示例中的&mut MyType2
。
共享引用很简单:因为它们是
Copy
,您只需要求Copy
:
struct MyType1;
struct MyType2;
trait MyTrait {}
impl MyTrait for &MyType1 {}
impl MyTrait for &mut MyType2 {}
fn my_function<T>(x: T)
where
T: MyTrait + Copy,
{
some_library_function(x);
some_library_function(x);
}
fn some_library_function(x: impl MyTrait) {}
但是您还想支持可变引用,这就是事情变得更加复杂的地方。
看,可变引用不是
Copy
。它们不可能——如果我能够复制可变引用,我就可以很容易地创建别名引用,从这里开始,通往不健全的道路真的很短。但他们仍然有“存在”的“幻想”。当我有一个可变引用时,我可以多次移动它 - 如何移动?
秘密是再借。当您移动可变引用时,编译器实际上并不会移动它 - 相反,它会重新借用
它,这是一个可以显式编写为Copy
的操作。重新借用是一种形式为 &mut *reference
的操作。也就是说,您短期借用了(长)可变引用。该引用在该(短时间内)内变得不可用,但作为交换,您会获得一个在短时间内有效的新的可变引用。
<'a: 'b, 'b> &'b mut &'a mut T -> &'b mut T