移出泛型类型的共享引用
Moving out of a shared reference on a generic type
我正在尝试创建一个函数,该函数使用迭代器为每行中最大的 i64
获取元组“坐标”的 &[Vec<u64>]
和 returns 向量。我让它在具体类型上工作,但我希望它在 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
还是我可以提供更通用的内容?
IntoIterator::into_iter
获取 self
,这意味着它消耗(或 移动 )对象。
您已经添加了绑定 T: IntoIterator
,因为这是唯一的 IntoIterator
,编译器将使用 T
的实现。在 T
上调用 into_iter
将始终移动该值,这是不正确的,因为该函数仅被赋予了对它的引用,而 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<_>>()
}
要回答第二个问题,是的,您可以使项目通用。您可以省略它,然后指定代码所需的范围,而不是指定具体类型。您正在按值移动它,因此它需要是 Copy
(否则您需要更改代码以克隆它并改为 Clone
),并且您正在使用 max_by_key
,这要求它是 Ord
。函数签名将是:
fn find_largest_per_row<'a, T>(input: &'a [T]) -> Vec<(usize, usize)>
where
&'a T: IntoIterator,
<&'a T as IntoIterator>::Item: Ord + Copy,
另请参阅:
我正在尝试创建一个函数,该函数使用迭代器为每行中最大的 i64
获取元组“坐标”的 &[Vec<u64>]
和 returns 向量。我让它在具体类型上工作,但我希望它在 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
还是我可以提供更通用的内容?
IntoIterator::into_iter
获取 self
,这意味着它消耗(或 移动 )对象。
您已经添加了绑定 T: IntoIterator
,因为这是唯一的 IntoIterator
,编译器将使用 T
的实现。在 T
上调用 into_iter
将始终移动该值,这是不正确的,因为该函数仅被赋予了对它的引用,而 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<_>>()
}
要回答第二个问题,是的,您可以使项目通用。您可以省略它,然后指定代码所需的范围,而不是指定具体类型。您正在按值移动它,因此它需要是 Copy
(否则您需要更改代码以克隆它并改为 Clone
),并且您正在使用 max_by_key
,这要求它是 Ord
。函数签名将是:
fn find_largest_per_row<'a, T>(input: &'a [T]) -> Vec<(usize, usize)>
where
&'a T: IntoIterator,
<&'a T as IntoIterator>::Item: Ord + Copy,
另请参阅: