【问题标题】:What is the idiomatic way of converting a Vec of references to a Vec of values?将引用的 Vec 转换为值的 Vec 的惯用方式是什么?
【发布时间】:2019-04-06 13:06:43
【问题描述】:

我的函数返回一个元组引用的Vec,但我需要一个元组的Vec

use std::collections::HashSet;

fn main() {
    let maxs: HashSet<(usize, usize)> = HashSet::new();
    let mins: HashSet<(usize, usize)> = HashSet::new();
    let intersection = maxs.intersection(&mins).collect::<Vec<&(usize, usize)>>();
}

我应该如何进行转换?

错误:

19 |     maxs.intersection(&mins).collect::<Vec<&(usize, usize)>>()
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
   |
   = note: expected type `std::vec::Vec<(usize, usize)>`
          found type `std::vec::Vec<&(usize, usize)>`

我是using a for loop to do the conversion,但我不喜欢它,我认为应该有一种模式惯用的方式:

for t in maxs.intersection(&mins).collect::<Vec<&(usize, usize)>>().iter() {
    output.push(**t);
}

【问题讨论】:

    标签: reference rust iterator


    【解决方案1】:

    从 1.36.0 更新

    Rust 1.36.0 引入了copied,它的工作方式类似于cloned,但使用了Copy trait,它要求副本便宜(例如,仅memcpy)。如果您有基本类型或实现 Copy 的类型,则可以使用它。


    要使您的示例有效,请使用cloned,然后使用collect

    let maxs: HashSet<(usize,usize)> = HashSet::new();
    let mins: HashSet<(usize,usize)> = HashSet::new();
    let output: Vec<(usize, usize)> = maxs.intersection(&mins).cloned().collect();
    

    此解决方案适用于实现 Clone 以外的任何类型:

    pub fn clone_vec<T: Clone>(vec: Vec<&T>) -> Vec<T> {
        vec.into_iter().cloned().collect()
    }
    

    如果您的函数接受切片,则必须使用 cloned 两次。

    pub fn clone_slice<T: Clone>(slice: &[&T]) -> Vec<T> {
        slice.iter().cloned().cloned().collect()
    }
    

    原因是iter() 在切片的引用上返回了一个迭代器,这导致了&amp;&amp;T


    如果你碰巧有一个没有实现Clone的类型,你可以用map模仿这种行为

    pub struct Foo(u32);
    
    impl Foo {
        fn dup(&self) -> Self {
            Foo(self.0)
        }
    }
    
    pub fn clone_vec(vec: Vec<&Foo>) -> Vec<Foo> {
        vec.into_iter().map(|f| f.dup()).collect()
    }
    
    pub fn clone_vec2(vec: Vec<&Foo>) -> Vec<Foo> {
        // this function is identical to `clone_vec`, but with another syntax
        vec.into_iter().map(Foo::dup).collect()
    }
    

    (playground)

    【讨论】:

    • 是的,它就像一个魅力!关键是在collect() 之前而不是之后添加一些东西。很好!但是(我现在只是好奇)如果我们已经有一个引用向量会发生什么?我们想将它们转换为值向量吗?在这种情况下我们是否也应该使用cloned()
    • 是的。函数ret_tup 正是这样做的。
    • 这适用于实现Clone的每一种类型——也许你可以展示一下适用于任何实现Clone的类型的通用版本?
    • 你不能使用into_iter——你可以,而且函数确实拥有切片,它只是有同样的问题。
    • @lucidbrot “向量迭代器迭代引用”:不是吗?切片iter() 函数可以。你是这个意思吗?如果是,原因是into_iter 消耗了Vec,这是不可能的,因为你只有一个借来的切片(&amp;[T])。你不拥有它,因此你只能迭代它的引用。
    猜你喜欢
    • 2022-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多