Rust 泛型类型边界允许任何实现特征的引用类型(共享或可变),同时保持引用特征

问题描述 投票:0回答:1

有没有一种方法可以编写

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

rust
1个回答
0
投票

共享引用很简单:因为它们是

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

© www.soinside.com 2019 - 2024. All rights reserved.