我遇到了一个问题,该特征可以返回对以self为单位的数据的引用. 这是一个最小的例子:

trait A<T> {
    fn emit_symbol(&mut self) -> T;
}

fn via_ans<'a>(emitter: &'a mut impl A<char>) -> String {
    let mut rval = String::new();
    for _ in 0..30 {
        let ch = emitter.emit_symbol();
        rval.push(ch)
    }
    rval
}

struct Hippo<T> {
    things: Vec<T>,
}

impl<T> A<&T> for Hippo<T> {
    fn emit_symbol(&mut self) -> &T {
        &self.things[2]
    }
}

给出错误

error: `impl` item signature doesn't match `trait` item signature
  --> src/b.rs:19:5
   |
2  |     fn emit_symbol(&mut self) -> T;
   |     ------------------------------- expected `fn(&'1 mut b::Hippo<T>) -> &'2 T`
...
19 |     fn emit_symbol(&mut self) -> &T {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut b::Hippo<T>) -> &'1 T`
   |
   = note: expected signature `fn(&'1 mut b::Hippo<T>) -> &'2 T`
              found signature `fn(&'1 mut b::Hippo<T>) -> &'1 T`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
  --> src/b.rs:2:34
   |
2  |     fn emit_symbol(&mut self) -> T;
   |                                  ^ consider borrowing this type parameter in the trait

如果我将生命周期添加到trait中为&'s self,那么实现就会工作,但我在使用trait方法的循环中遇到了新错误.

trait A<'s, T> {
    fn emit_symbol(&'s mut self) -> T;
}

fn via_ans<'a: 'b, 'b>(emitter: &'a mut impl A<'b, char>) -> String {
    let mut rval = String::new();
    for _ in 0..30 {
        let ch = emitter.emit_symbol();
        rval.push(ch)
    }
    rval
}

struct Hippo<T> {
    things: Vec<T>,
}

impl<'s, T> A<'s, &'s T> for Hippo<T> {
    fn emit_symbol(&'s mut self) -> &'s T {
        &self.things[2]
    }
}

给出错误

error[E0499]: cannot borrow `*emitter` as mutable more than once at a time
  --> src/main.rs:10:18
   |
7  | fn via_ans<'a: 'b, 'b>(emitter: &'a mut impl A<'b, char>) -> String {
   |                    -- lifetime `'b` defined here
...
10 |         let ch = emitter.emit_symbol();
   |                  ^^^^^^^--------------
   |                  |
   |                  `*emitter` was mutably borrowed here in the previous iteration of the loop
   |                  argument requires that `*emitter` is borrowed for `'b`

这是Rust的borrow 判断器的缺点,还是还有其他问题?

如何调整此特征以在我的应用程序中工作?

推荐答案

第二种方法的问题在于,由于impl A<'b, char>是函数的参数,因此编译器只能为'b Select single的生存期,并且由于它是从函数外部传递的,该生存期也持续整个函数.因此,当您在第一次调用emit_symbol时borrow emitter时,该borrow 直到函数结束后才会释放.

这是Higher Ranked Trait Bound (HRTB)的典型应用程序:

fn via_ans<'a>(emitter: &'a mut impl for<'b> A<'b, char>) -> String {
    let mut rval = String::new();
    for _ in 0..30 {
        let ch = emitter.emit_symbol();
        rval.push(ch)
    }
    rval
}

因为这现在意味着emitter必须是在every生命周期内实现A的类型,因此编译器可以为每次循环迭代 Select 不同的类型.

事实上,您的问题几乎与serde有时必须用Deserialize特征来解决的问题相同,为了隐藏不太漂亮的HTB,他们添加了一个additional trait DeserializeOwned,您也可以将其应用于您的 case :

trait AOwned<T>: for<'a> A<'a, T> {}
impl<S, T> AOwned<T> for S where S: for<'a> A<'a, T> {}
fn via_ans<'a>(emitter: &'a mut impl AOwned<char>) -> String {
    //…
}

Rust相关问答推荐

为什么我需要在这个代码示例中使用&

如何为utoipa中的可选查询参数生成OpenAPI模式?

两个相关特征的冲突实现错误

如何将`Join_all``Vec<;Result<;Vec<;Foo&>;,Anywhere::Error&>;`合并到`Result<;Vec<;Foo&>;,Anywhere::Error&>;`

在0..1之间将U64转换为F64

如何创建一个可变的嵌套迭代器?

Rust 中什么时候可以返回函数生成的字符串切片&str?

使用 pyo3 将 Rust 转换为 Python 自定义类型

根据掩码将 simd 通道设置为 0 的惯用方法?

需要一个有序向量来进行 struct 初始化

为什么我的trait 对象类型不匹配?

Rust并发读写引起的死锁问题

如何将 &[T] 或 Vec<T> 转换为 Arc<Mutex<[T]>>?

Rust中如何实现一个与Sized相反的负特性(Unsized)

从光标位置旋转精灵

push 方法是否取得所有权?

如何限制通用 const 参数中允许的值?

预期的整数,找到 `&{integer}`

从 Cranelift 发出 ASM

如何为返回正确类型的枚举实现 get 方法?