首页 文章

过滤器关闭时借用的时间不够长

提问于
浏览
2

当我尝试编译此代码(playground)时:

fn main() {
    let iter = "abc123".chars().filter(&|&c: &char| c.is_digit(10));
    match iter.clone().take(3).count() {
        3 => println!("{}", iter.collect::<String>()),
        _ => {}
    }
}

我收到以下错误:

error: borrowed value does not live long enough
 --> test.rs:2:41
  |
2 |     let iter = "abc123".chars().filter(&|c: &char| c.is_digit(10));
  |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here
  |                                         |
  |                                         temporary value created here
...
7 | }
  | - temporary value needs to live until here
  |
  = note: consider using a `let` binding to increase its lifetime

我理解错误有助于告诉我在 let f = &|c: &char| c.is_digit(10);working code)上面的行中声明闭包,但为什么这是必要的呢?

我也不确定为什么闭包必须包含两个引用 - &|c: &char| . 不是 "abc123".chars() 只是创建一个字符迭代器?

1 回答

  • 5

    但为什么这有必要呢?

    我真的不知道如何解释它比错误消息更好:

    临时 Value 只存在这里
    在这里创建临时值

    您正在语句中创建临时值(闭包本身),然后引用它 . 当语句结束时,该值被销毁 - 没有任何东西拥有它!问题是代码试图保持对现在被破坏的值的引用 . 如果编译器允许这样做,那么当它使用该引用时,谁知道将访问哪些随机数据 .

    闭包必须包含两个引用

    嗯,它不必 . filter(|c| c.is_digit(10)) 工作得很好;类型推断允许 c 自动输入 &char . 仅 &c 模式匹配并自动取消引用该值 . 这是多余的,因为方法调用automatically dereference .

    更大的问题是代码试图克隆包含闭包的迭代器,你不能这样做(1234(善良,人们在提问之前拒绝搜索)) . 你选择解决这个问题的聪明方法是克隆对闭包的引用,这很好 .

    问题循环回到引用语句末尾被销毁的东西 .


    If 目标是忽略所有非数字,跳过前3位数然后收集其余数字,你可以使用Iterator::skip

    let iter = "abc123".chars().filter(|c| c.is_digit(10));
    let together: String = iter.skip(3).collect();
    println!("{}", together);
    

    If 目标是仅取前三位数,当且仅当有三位数时,我可能总是收集这些数字,并检查是否结束:

    let mut iter = "abc123".chars().filter(|c| c.is_digit(10));
    let together: String = iter.by_ref().take(3).collect();
    
    if iter.next().is_none() {
        println!("{}", together);
    }
    

    这使用Iterator::by_ref . by_ref 不是使用迭代器,而是创建一个可变引用 . 对迭代器的可变引用也实现 Iterator ,因此调用 takecollect 工作正常 . 但是,当这些完成后, iter 仍然有效 .

相关问题