元组 Vec 的部分移动

Nil*_*dré 10 move move-semantics rust

我有 a Vec<(String, i64)>,需要迭代Strings 并移动它们,然后迭代i64s 。

但是,如果我移动Strings,我必须i64再次将 s 存储到另一个 s 中Vec

let l: Vec<_> = l
    .into_iter()
    .map(|(string, int)| {
        drop(string);
        int
    })
    .collect();
                           
for i in l {
    process(i);
}
Run Code Online (Sandbox Code Playgroud)

如何分别迭代Strings 和i64s 而不会产生任何额外的性能开销。

目前我能想到的唯一不会导致额外操作的解决方案就是将Strings 和i64s 分开存储。

use*_*968 12

您可以在第一遍std::mem::take()迭代时使用 来获取元素的所有权,同时将非分配放在其位置。这使您可以保持其原始形式,因此不需要额外的容器。VecStringDefaultVec

fn foo(mut inp: Vec<(String, i64)>) {
    // First pass over the Vec "extracts" the owned Strings, replacing the content
    // in the Vec by a non-allocating empty String, which is close to zero cost;
    // this leaves the Vec as is, so no intermediate representation is needed.
    for s in inp.iter_mut().map(|(s, _)| std::mem::take(s)) {
        // Process String
    }

    // Something happens

    // Second pass ignores the empty strings, processes the integers
    for i in inp.into_iter().map(|(_, i)| i) {
        // Process the integers
    }
}
Run Code Online (Sandbox Code Playgroud)


Joe*_*gyu 7

如果列表的类型可以更改为Vec<Option<String>, i64>from Vec<String, i64>,那么您可以尝试以下方式。

fn main() {
    let mut l = Vec::new();
    l.push((Some("a".to_string()), 1i64));
    l.push((Some("b".to_string()), 2));
    l.push((Some("c".to_string()), 3));
    l.push((Some("d".to_string()), 4));
    
    l.iter_mut().for_each(|(s, _)| {
        if let Some(x) = s.take() { 
            println!("Processing string: {}", x);
        }
    });

    l.iter().for_each(|(_, i)| {
        println!("Processing int: {}", i);
    });
}
Run Code Online (Sandbox Code Playgroud)

操场