rust 泛型函数中的生存期推导和借用(泛型测试所需)

n9vozmp4  于 2023-02-12  发布在  其他
关注(0)|答案(1)|浏览(121)

假设一个简单的trait允许附加一个对象引用,我在这里使用String使代码简单一些。

trait Attachable<'a> {
    fn new() -> Self;
    fn attach(&mut self, value: &'a String);
}

一个简单的实现可能如下所示:

struct SomeAttachable<'a> {
    id: Option<&'a String>,
}

impl<'a> Attachable<'a> for SomeAttachable<'a> {
    fn new() -> Self {
        Self { id: None }
    }
    fn attach(&mut self, value: &'a String) {
        self.id = Some(value)
    }
}

而且使用它是开箱即用的。

let mut object = SomeAttachable::new();
let value = "hello".to_string();
object.attach(&value);

但是当它被放到一个泛型函数中,而这个泛型函数中只提供了可附加类型时,它就中断了。

fn do_stuff<'a, T: Attachable<'a>>() {
    let mut object = T::new();
    let value: String = "hello".to_string();
    object.attach(&value); // breaks here since value does not live long enough
}

我假设在调用函数do_stuff时检测到了生存期,然后value有一个“错误的”生存期要求。我如何在do_stuff的实现中纠正生存期问题呢?
将函数签名调整为:

fn do_stuff_with_argument<'a, T: Attachable<'a>>(value: &'a String) {
    let mut bla = T::new();
    bla.attach(&value);
}

可以解决这个问题,因为现在可以再次正确地检测到生存期,因为它是输入引用参数的一部分。但这对我来说不是一个合适的解决方案。do_stuff函数应该处理函数内部的所有逻辑,而不需要任何函数参数。只允许使用通用参数,如生存期和类型。
我假设我可能必须使用更高等级的特质界限并实现do_stuff,如下所示:

fn do_stuff<T>()
where
    T: for<'a> Attachable<'a>,
{
    let mut object = T::new();
    let value: String = "hello".to_string();
    object.attach(&value);
}

但是这导致Rust抱怨Attachable的实现对于SomeAttachable来说不够通用。
提供一些背景:我需要基于generic-test crate的单元测试,在那里验证trait的行为。

ycl3bljg

ycl3bljg1#

你可以使用AttachableTag trait,它有一个泛型关联类型,可以为任何'a提供一个Attachable<'a>(你也可以使用相同的trait和类型,但我更喜欢这样):

trait AttachableTag {
    type Attachable<'b>: Attachable<'b>;
}

trait Attachable<'a> {
    fn new() -> Self;
    fn attach(&mut self, value: &'a String);
}

struct SomeAttachableTag;

impl AttachableTag for SomeAttachableTag {
    type Attachable<'b> = SomeAttachable<'b>;
}

struct SomeAttachable<'a> {
    id: Option<&'a String>,
}

impl<'a> Attachable<'a> for SomeAttachable<'a> {
    fn new() -> Self {
        Self { id: None }
    }
    fn attach(&mut self, value: &'a String) {
        self.id = Some(value)
    }
}

fn do_stuff<T: AttachableTag>() {
    let mut object = T::Attachable::new();
    let value: String = "hello".to_string();
    object.attach(&value);
}

do_stuff::<SomeAttachableTag>();

但是,这会产生错误:

error[E0597]: `value` does not live long enough
  --> src/main.rs:32:19
   |
32 |     object.attach(&value);
   |                   ^^^^^^ borrowed value does not live long enough
33 | }
   | -
   | |
   | `value` dropped here while still borrowed
   | borrow might be used here, when `object` is dropped and runs the destructor for type `<T as AttachableTag>::Attachable<'_>`
   |
   = note: values in a scope are dropped in the opposite order they are defined

要修复此问题,请将value的声明移到object之前:

fn do_stuff<T: AttachableTag>() {
    let value: String = "hello".to_string();
    let mut object = T::Attachable::new();
    object.attach(&value);
}

相关问题