即使“自身”寿命足够长,借入的值也无法长期存储“ AsRef”结果

时间:2018-11-22 20:35:45

标签: generics rust traits lifetime

我有一个将某些功能包装在切片上的结构:

use std::fmt::Debug;

struct SliceWrapper<'a, T: Debug + Copy + 'a> {
    slice: &'a [T],
    pos: usize,
}

我想为支持From的每个元素实现AsRef<T: Debug + Copy + 'a>特质,像这样:

impl<'a, T: Debug + Copy + 'a, R: AsRef<[T]> + 'a> From<R> for SliceWrapper<'a, T> {
    fn from(slice: R) -> Self {
        Self {
            slice: slice.as_ref(),
            pos: 0,
        }
    }
}

我得到了错误:

error[E0597]: `slice` does not live long enough
  --> src/lib.rs:11:20
   |
11 |             slice: slice.as_ref(),
   |                    ^^^^^ borrowed value does not live long enough
...
14 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 8:6...
  --> src/lib.rs:8:6
   |
8  | impl<'a, T: Debug + Copy + 'a, R: AsRef<[T]> + 'a> From<R> for SliceWrapper<'a, T> {
   |      ^^

我不明白这一点,因为我说Rslice)的寿命必须与我的SliceWrapper一样长,而据我了解,AsRef<_>selfslice)继承生命周期...

2 个答案:

答案 0 :(得分:3)

夜间的完整错误消息非常清楚地说明了这里发生的情况。您将slice移到函数from()中,然后使用as_ref()借用它,然后将其放在范围的末尾:

8  | impl<'a, T: Debug + Copy + 'a, R: AsRef<[T]> + 'a> From<R> for SliceWrapper<'a, T> {
   |      -- lifetime `'a` defined here
9  |     fn from(slice: R) -> Self {
10 |         Self{ slice: slice.as_ref(), pos: 0 }
   |                      ^^^^^---------
   |                      |
   |                      borrowed value does not live long enough
   |                      argument requires that `slice` is borrowed for `'a`
11 |     }
   |     - `slice` dropped here while still borrowed

您正试图创建一个可以终身使用'a的借项,但是您要借用的所有者slice的寿命不足。

From特性似乎不适用于此用例。该特征的想法是将某些数据的所有权移至新的类型,但是您的SliceWrapper不具有所有权。我建议写一个自定义构造函数,而不是引用R

答案 1 :(得分:1)

您可以将转换限制为引用参数,然后有一种很好的方式来表达所需的借用-生存期取自输入引用:

impl<'a, T, R> From<&'a R> for SliceWrapper<'a, T>
where
    T: Debug + Copy + 'a,
    R: AsRef<[T]>
{
    fn from(slice: &'a R) -> Self {
        Self {
            slice: slice.as_ref(),
            pos: 0,
        }
    }
}

现在,您可以按照原来的推理了。 您有一个AsRef给您:&'x self -> &'x [T]代表任何'x,然后在其中输入&'a R,这样您就得到了&'a [T]

参考引用From有时存在,我认为这在类似引用到引用的转换中特别合适。 std中的一个示例是impl<'a> From<&'a str> for Cow<'a, str>