假设有一个允许附加对象引用的简单特征.我在这里使用了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箱的单元测试中需要这样做,其中验证了特征的行为.

推荐答案

您可以使用一个AttachableTag特征,以及一个为任意'a提供Attachable<'a>的泛型关联类型(您也可以使用相同的特征和类型,但我更喜欢这种方式):

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);
}

Rust相关问答推荐

如何在Rust中为具有多个数据持有者的enum变体编写文档 comments ?

使用元组执行条件分支的正确方法

如何在原始字符串中转义";#和#";

抽象RUST中的可变/不可变引用

如何在Tauri中将变量从后端传递到前端

如何提高自定义迭代器的`extend`性能

使用铁 rust S还原对多个数组执行顺序kronecker积

在Rust中是否可以使用Rc自动化约束传播

无法定义名为&new&的关联函数,该函数的第一个参数不是self

Rust中WPARAM和VIRTUAL_KEY的比较

try 实现线程安全的缓存

具有多个键的 HashMap

unwrap 选项类型出现错误:无法移出共享引用后面的*foo

Rust typestate 模式:实现多个状态?

Rust 中的生命周期:borrow 的 mut 数据

如何递归传递闭包作为参数?

如何从 x86_64 Mac 构建 M1 Mac?

`if let` 只是另一种编写其他 `if` 语句的方式吗?

在 Rust 中有条件地导入?

如何从 Rust 中不同类型的多个部分加入 Path?