在闭包中使用split_at_mut生锈错误E0495

时间:2017-02-10 14:46:07

标签: rust lifetime borrow-checker

我遇到了一个“错误[E0495]:无法推断autoref的适当生命周期,因为需求冲突”使用这个简单的函数:

fn assign_split_at_mut<'a, 'b, T>(s: &'b mut &'a mut [T], mid: usize) -> &'a mut [T] {
    let (x, y) = (*s: &'a mut [T]).split_at_mut(mid);
    *s = y;
    x
}

我写了一个playpen example,其中包含unsafe split_at_mut变体fn assign_split_at_mut_unsafe<'a, T>(s: &mut &'a mut [T], mid: usize) -> &'a mut [T] { let len = (*s: &'a mut [T]).len(); let ptr = (*s: &'a mut [T]).as_mut_ptr(); unsafe { use std::slice::from_raw_parts_mut; assert!(mid <= len); *s: &'a mut [T] = from_raw_parts_mut(ptr.offset(mid as isize), len - mid); from_raw_parts_mut(ptr, mid) } }

pub fn slice_header<'a>(&'static self, mut header: &'a mut [u8])
  -> MyResult<HeaderRefs<'a>>
{
    // ...
    let take = |l: usize| -> &'a mut [u8] {
        let (x,y) = header.split_at_mut(l);
        header = y;  x
    };
    let hr = HeaderRefs {
        params: self,
        alpha: array_mut_ref![take(32),0,32],
        gamma: array_mut_ref![take(16),32,16],
        beta: take(self.beta_length as usize),
        surb_log: take(self.surblog_length as usize),
        surb: take(self.surb_length()),
    };
    // ...
    Ok(hr)
}

事实上,我想大致写下这个:

let (alpha,header) = header.split_at_mut(32);
let (gamma,header) = header.split_at_mut(16);
// ...

我相信如果我简单地写出一堆

它会工作正常
Sub CopyShortageData()
  intFoundRow = Sheets("PP1 & PP2 Shortage list").Range("A1").Value
  Range(Sheets("PP1 Paint plan").Range("A" & intFoundRow & ":AF" & intFoundRow), Sheets("PP1 Paint plan").Range("A" & intFoundRow & ":AF" & intFoundRow).End(xlDown)).Copy
  Sheets("Your destination sheet").Range("A2").PasteSpecial xlPasteAll
End Sub

如果我将它们放入数组中,它可能会起作用。我无法使用闭合装置,看起来更干净。

2 个答案:

答案 0 :(得分:2)

这是一个借用问题:

fn assign_split_at_mut<'a, 'b, T>(s: &'b mut &'a mut [T], mid: usize) -> &'a mut [T] {
    let (x, y) = (*s: &'a mut [T]).split_at_mut(mid);
    *s = y;
    x
}

具体而言,split_at_mut借用了s,因此您无法 在借用时分配给s

要理解这个问题,想象一下我们在这里讨论向量,s: &mut Vec<T>:你可以先从Vec借一个切片,然后用s来改变它。 / p>

这就是Rust指定借用整个访问路径的原因,而不仅仅是叶子。

好的,现在呢?

如@nox所述,解决方案是跳舞&#34;:

  • &'a mut [T]的所有权从s移至本地变量
  • 借用此本地变量
  • 分配给s

这样,借用检查器是安抚的,因为它知道修改s不会影响局部变量及其借用。

根据具体情况,有多种方法可以将所有权从&mut X移出,有些常见方法是:

  • std::mem::replace
  • std::mem::swap
  • Option::take如果XOption
  • ...

在您的情况下,replace更简单。 @nox提供的解决方案非常简单:

fn reserve<'heap, T>(heap: &mut &'heap mut [T], len: usize) -> &'heap mut [T] {
    let tmp: &'heap mut [T] = ::std::mem::replace(&mut *heap, &mut []);
    let (reserved, tmp) = tmp.split_at_mut(len);
    *heap = tmp;
    reserved
}

答案 1 :(得分:0)

IRC用户nox使用composer create-project laravel/laravel %project% 5.4.* composer require "laravelcollective/html" 移动首先需要突变的mem::replace,提供了一个干净的答案:

&mut [T]