递归特征函数的生命周期问题

时间:2016-09-17 19:36:20

标签: rust mergesort lifetime

我很难将独立的merge_sort函数转换为Vec<T>的特征。似乎我遇到了合并排序算法工作方式的生命周期错误。

我已经尝试在函数和特征声明中指定生命周期,但它仍然给我一个类似的错误。

我对生命的研究包括......

  • 有效生锈
  • The Rust book
  • 一些关于有生之年的YouTube视频
  • Stack Overflow关于生命周期的大多数问题

这是代码

trait MergeSortable<T> {
    fn merge_sort(&mut self);
    fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T>;
}

impl<T: Ord + Clone + PartialEq> MergeSortable<T> for Vec<T> {
    fn merge_sort(&mut self) {
        if self.len() <= 1 {
            return;
        }
        let mid = self.len() / 2;
        let mut left = self[..mid].to_vec();
        left.merge_sort();
        let mut right = self[mid..].to_vec();
        right.merge_sort();
        self = self._merge(&mut left, &mut right);
    }

    fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
        if left.len() == 0 {
            return right;
        }
        if right.len() == 0 {
            return left;
        }
        if left[0] < right[0] {
            let mut v: Vec<T> = Vec::new();
            v.push(left[0].clone());
            v.extend_from_slice(&self._merge(&mut left[1..].to_vec().clone(), &mut right.clone())[..]);
            return &mut v;
        }
        let mut v: Vec<T> = Vec::new();
        v.push(right[0].clone());
        v.extend_from_slice(&self._merge(&mut left.clone(), &mut right[1..].to_vec().clone())[..]);
        return &mut v;
    }
}

Playground

错误:

error: lifetime of reference outlives lifetime of borrowed content... [E0312]
  --> <anon>:27:20
   |>
27 |>             return left;
   |>                    ^^^^
note: ...the reference is valid for the anonymous lifetime #1 defined on the block at 22:75...
  --> <anon>:22:76
   |>
22 |>     fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
   |>                                                                            ^
note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the block at 22:75
  --> <anon>:22:76
   |>
22 |>     fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
   |>                                                                            ^

error: lifetime of reference outlives lifetime of borrowed content... [E0312]
  --> <anon>:24:20
   |>
24 |>             return right;
   |>                    ^^^^^
note: ...the reference is valid for the anonymous lifetime #1 defined on the block at 22:75...
  --> <anon>:22:76
   |>
22 |>     fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
   |>                                                                            ^
note: ...but the borrowed content is only valid for the anonymous lifetime #3 defined on the block at 22:75
  --> <anon>:22:76
   |>
22 |>     fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
   |>                                                                            ^
help: consider using an explicit lifetime parameter as shown: fn _merge<'a, 'b>(&'a self, left: &'a mut Vec<T>, right: &'b mut Vec<T>)
 -> &mut Vec<T>
  --> <anon>:22:5
   |>
22 |>     fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
   |>     ^

2 个答案:

答案 0 :(得分:4)

_merge实际上并不需要self参数。我们将其删除:

use std::cmp::Ord;
use std::clone::Clone;

trait MergeSortable<T> {
    fn merge_sort(&mut self);
    fn _merge(left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T>;
}

impl<T: Ord + Clone + PartialEq> MergeSortable<T> for Vec<T> {
    fn merge_sort(&mut self) {
        if self.len() <= 1 {
            return;
        }
        let mid = self.len() / 2;
        let mut left = self[..mid].to_vec();
        left.merge_sort();
        let mut right = self[mid..].to_vec();
        right.merge_sort();
        self = Self::_merge(&mut left, &mut right);
    }

    fn _merge(left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
        if left.len() == 0 {
            return {right};
        }
        if right.len() == 0 {
            return {left};
        }
        if left[0] < right[0] {
            let mut v: Vec<T> = Vec::new();
            v.push(left[0].clone());
            v.extend_from_slice(&Self::_merge(&mut left[1..].to_vec().clone(), &mut right.clone())[..]);
            return &mut v;
        }
        let mut v: Vec<T> = Vec::new();
        v.push(right[0].clone());
        v.extend_from_slice(&Self::_merge(&mut left.clone(), &mut right[1..].to_vec().clone())[..]);
        return &mut v;
    }
}

现在我们得到了一个不同的错误:

error: missing lifetime specifier [--explain E0106]
 --> <anon>:6:57
  |>
6 |>     fn _merge(left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T>;
  |>                                                         ^^^^^^^^^^^
help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `left` or `right`

error: missing lifetime specifier [--explain E0106]
  --> <anon>:22:57
   |>
22 |>     fn _merge(left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T> {
   |>                                                         ^^^^^^^^^^^
help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `left` or `right`

这有助于我们理解第一个问题:当有self参数并且返回值是引用时,编译器将推断返回引用的生命周期与{{1}相关联}。在这里根本不是这样的!通过删除self参数,编译器面临两个作为引用的参数,并且当前的省略规则使得必须必须指定显式生存期。

所以,让我们这样做!

self

但现在,我们遇到了更多错误。让我们关注这个:

use std::cmp::Ord;
use std::clone::Clone;

trait MergeSortable<T> {
    fn merge_sort(&mut self);
    fn _merge<'a>(left: &'a mut Vec<T>, right: &'a mut Vec<T>) -> &'a mut Vec<T>;
}

impl<T: Ord + Clone + PartialEq> MergeSortable<T> for Vec<T> {
    fn merge_sort(&mut self) {
        if self.len() <= 1 {
            return;
        }
        let mid = self.len() / 2;
        let mut left = self[..mid].to_vec();
        left.merge_sort();
        let mut right = self[mid..].to_vec();
        right.merge_sort();
        self = Self::_merge(&mut left, &mut right);
    }

    fn _merge<'a>(left: &'a mut Vec<T>, right: &'a mut Vec<T>) -> &'a mut Vec<T> {
        if left.len() == 0 {
            return right;
        }
        if right.len() == 0 {
            return left;
        }
        if left[0] < right[0] {
            let mut v: Vec<T> = Vec::new();
            v.push(left[0].clone());
            v.extend_from_slice(&Self::_merge(&mut left[1..].to_vec().clone(), &mut right.clone())[..]);
            return &mut v;
        }
        let mut v: Vec<T> = Vec::new();
        v.push(right[0].clone());
        v.extend_from_slice(&Self::_merge(&mut left.clone(), &mut right[1..].to_vec().clone())[..]);
        return &mut v;
    }
}

您尝试返回对本地变量的引用。你不能这样做:你必须返回值本身,就像你在原始函数中所做的那样。有关详细信息,请参阅Return local String as a slice (&str)

也许您不知道的一个技巧是,您可以通过指定其引用(error: `v` does not live long enough --> <anon>:33:25 |> 33 |> return &mut v; |> ^ note: reference must be valid for the lifetime 'a as defined on the block at 22:81... --> <anon>:22:82 |> 22 |> fn _merge<'a>(left: &'a mut Vec<T>, right: &'a mut Vec<T>) -> &'a mut Vec<T> { )来替换引用后面的值。

*self = new_value

我还会考虑将use std::cmp::Ord; use std::clone::Clone; trait MergeSortable<T> { fn merge_sort(&mut self); fn _merge(left: Vec<T>, right: Vec<T>) -> Vec<T>; } impl<T: Ord + Clone + PartialEq> MergeSortable<T> for Vec<T> { fn merge_sort(&mut self) { if self.len() <= 1 { return; } let mid = self.len() / 2; let mut left = self[..mid].to_vec(); left.merge_sort(); let mut right = self[mid..].to_vec(); right.merge_sort(); *self = Self::_merge(left, right); } fn _merge(left: Vec<T>, right: Vec<T>) -> Vec<T> { if left.len() == 0 { return right; } if right.len() == 0 { return left; } if left[0] < right[0] { let mut v: Vec<T> = Vec::new(); v.push(left[0].clone()); v.extend_from_slice(&Self::_merge(left[1..].to_vec(), right)[..]); return v; } let mut v: Vec<T> = Vec::new(); v.push(right[0].clone()); v.extend_from_slice(&Self::_merge(left, right[1..].to_vec())[..]); return v; } } 移出特征并进入自由函数,这样您就不必编写_merge来调用它。

答案 1 :(得分:2)

在将其转换为特质版本之前,我不知道这是如何工作的。问题在于_merge

的签名
fn _merge(&self, left: &mut Vec<T>, right: &mut Vec<T>) -> &mut Vec<T>;

该签名实际上是以下的简写:

fn _merge<'a>(&'a self, left: &mut Vec<T>, right: &mut Vec<T>) -> &'a mut Vec<T>;

这意味着,返回的值必须是self的借用。在您的情况下,这完全不正确,因为您要么返回leftright,要么返回一个全新的向量(以及can't return a reference to a local variable)。修复它的最简单方法是返回Vec<T>。或者,如果您想在退回.clone()left时保存right,则可以返回Cow<[T]>(我认为它不值得)虽然)。

另外,我认为_merge并不真正属于特质,你甚至不在那里使用self。我只是把它变成了一个功能。