E0597 试图循环一个向量

E0597 trying to loop over an vector

我正在通过一些编程练习自学 Rust。这里我有一个 Vec<String> 我从一个文件中读出,我试图将每行中的字母放在 HashSet 中,然后取所有行的交集。

当我这样做时,我收到一条错误消息,提示我的循环变量寿命不够长。

我直觉哪里出了问题——我有一个变量 l,它的生命周期是循环的一次迭代,另一个变量 candidates 的生命周期是整个循环,第二个变量是从首先。但是我该如何解决这个问题?

let mut candidates = HashSet::<&u8>::new();
let mut sum = 0;
for l in lines { // lines is Vec<String>
    if candidates.len()==0 {
        candidates = HashSet::<&u8>::from_iter(l.as_bytes());
        println!("candidates = {:?}", candidates);
    } else if l.len() == 0 { // error message "borrow later used here"
        // end of group
        sum = sum + candidates.len();
        candidates = HashSet::<&u8>::new();
    } else {
        let h2 = HashSet::<&u8>::from_iter(l.as_bytes()); // error message "borrowed value does not live long enough"
        candidates = candidates.intersection(&h2).copied().collect();
        println!("candidates = {:?}", candidates);
    }
    println!("{}", l);
}

我尝试复制 l

let mut l2:String = "".to_string();
for l in lines {
    if candidates.len()==0 {
        l2 = l.to_string();
        candidates = HashSet::<&u8>::from_iter(l2.as_bytes());

但是我得到了一个不同的错误 error[E0506]: cannot assign to l2 because it is borrowed

as_bytes 将您的 l 字符串转换为字节切片。切片是对连续元素序列的引用。编译器指出在您的 for 循环结束时,引用无效。

一种解决方案是使用 &lines:

迭代字符串引用
    let mut candidates = HashSet::<&u8>::new();
    let mut sum = 0;
    for l in &lines { // <= HERE iter over String references which lives outside the for loop
        if candidates.len()==0 {
            candidates = HashSet::<&u8>::from_iter(l.as_bytes());
            println!("candidates = {:?}", candidates);
        } else if l.len() == 0 {
            // end of group
            sum = sum + candidates.len();
            candidates = HashSet::<&u8>::new();
        } else {
            let h2 = HashSet::<&u8>::from_iter(l.as_bytes());
            candidates = candidates.intersection(&h2).copied().collect();
            println!("candidates = {:?}", candidates);
        }
        println!("{}", l);
    }

第二种解决方案是复制 l 字符串。

    let mut candidates = HashSet::<u8>::new();
    let mut sum = 0;
    for l in lines { // lines is Vec<String>
        if candidates.len()==0 {
            candidates = HashSet::<u8>::from_iter(l.clone().into_bytes());
            println!("candidates = {:?}", candidates);
        } else if l.len() == 0 {
            // end of group
            sum = sum + candidates.len();
            candidates = HashSet::<u8>::new();
        } else {
            let h2 = HashSet::<u8>::from_iter(l.clone().into_bytes());
            candidates = candidates.intersection(&h2).copied().collect();
            println!("candidates = {:?}", candidates);
        }
        println!("{}", l);
    }

candidates 可以包含来自上一个循环迭代的对 l 的引用,但是 l 在每次循环迭代结束时被删除,因此会出现编译错误。你可以通过使用 into_bytes 而不是 as_bytes 来避免所有这些麻烦,这样你就可以获得拥有的值而不是引用。这是清理后的重构版本:

use std::collections::HashSet;

fn example(lines: Vec<String>) {
    let mut candidates: HashSet<u8> = HashSet::new();
    let mut sum = 0;

    for line in lines {
        dbg!(&line);
        let h2: HashSet<u8> = line.into_bytes().into_iter().collect();
        if candidates.is_empty() {
            candidates = h2;
        } else if h2.is_empty() {
            sum += candidates.len();
            candidates = HashSet::new();
        } else {
            candidates = candidates.intersection(&h2).copied().collect();
        }
        dbg!(&candidates);
    }
}

playground