首页 > 解决方案 > 移出泛型类型的共享引用

问题描述

我正在尝试创建一个函数,该函数使用迭代器获取&[Vec<u64>]并返回每行中最大的元组“坐标”向量。i64我让它在具体类型上工作,但我希望它是通用的,T并且限制在可迭代类型上。到目前为止我的代码:

fn find_largest_per_row<T>(input: &[T]) -> Vec<(usize, usize)> 
where
    T: IntoIterator<Item = u64>,
{
    input
        .iter()
        .enumerate()
        .map(|(r, v)| {
            v.into_iter()
                .enumerate()
                .max_by_key(|&(_, v)| v)
                .map(|(c, _)| (r, c))
                .unwrap()
        })
        .collect::<Vec<_>>()
}

我越来越:

cannot move out of `*v` which is behind a shared reference

我该如何解决这个问题?我意识到T这是一个参考,所以我尝试了.cloned(),但没有奏效。

另外,对于IntoIterator<Item=u64>,我需要指定u64还是可以提供更通用的内容?

标签: genericsrusttraitsmove-semantics

解决方案


IntoIterator::into_itertake self,这意味着它消耗(或移动)对象。

你已经添加了边界T: IntoIterator,因为这是唯一IntoIterator的,编译器将使用T' 实现。调用总是into_iterT移动值,这是不好的,因为该函数只被赋予了对它的引用,并且T可能没有Copy——事实上,因为Vec它绝对不是。

IntoIterator也适用于大多数对可迭代类型的引用,例如&Vec<T>,其中项目也是引用。这些是可以移动的,因为引用是Copy,所以当它们被移动时原始数据保持不变。

您可以像这样更改函数签名:

fn find_largest_per_row<'a, T>(input: &'a [T]) -> Vec<(usize, usize)>
where
    &'a T: IntoIterator<Item = &'a u64>,
{
    input
        .iter()
        .enumerate()
        .map(|(r, v)| {
            v.into_iter()
                .enumerate()
                .max_by_key(|&(_, v)| v)
                .map(|(c, _)| (r, c))
                .unwrap()
        })
        .collect::<Vec<_>>()
}

To answer the second question, yes, you can make the item generic. Instead of specifying a concrete type, you can omit it and then specify the bounds that the code requires. You are moving it by value, so it needs to be Copy (or else you need to change the code to clone it and make it Clone instead), and you are using max_by_key, which requires it to be Ord. The function signature would then be:

fn find_largest_per_row<'a, T>(input: &'a [T]) -> Vec<(usize, usize)>
where
    &'a T: IntoIterator,
    <&'a T as IntoIterator>::Item: Ord + Copy,

See also:


推荐阅读