英文:
Cannot return Iterator::Item from function
问题
这段代码的问题在于你尝试从一个Vec中移动出一个不实现Copy trait的类型。为了解决这个问题,你可以使用std::clone::Clone
trait来复制元素而不是移动它们。以下是修改后的代码片段:
#[derive(EnumIter)]
pub enum Colors {
Red,
Blue,
Purple
}
fn get_random_enum<T: Iterator>(iter: &mut T, rng: &mut Random) -> T::Item
where
T::Item: Clone, // 添加此行以指示T::Item必须实现Clone trait
{
let options = iter.collect::<Vec<_>>();
let count = options.len();
let idx = rng.rand_range(0, (count-1) as u32);
let item = options[idx as usize].clone(); // 使用clone方法来复制元素
item
}
fn main() {
let rng = create_MyRandomNumberGenerator();
let color = get_random_enum(&mut Colors::iter(), rng);
}
通过在get_random_enum
函数中添加T::Item: Clone
的约束,你告诉编译器要求T::Item
类型必须实现Clone trait,从而可以使用clone()
方法来复制元素而不是移动它们。这样,你的代码就不会再出现编译错误。
英文:
I'm writing a function to select a random variant from an enum with the help of the crate strum and its EnumIter derive macro:
#[derive(EnumIter)]
pub enum Colors {
Red,
Blue,
Purple
}
fn get_random_enum<T: Iterator>(iter: &mut T, rng: &mut Random) -> <T as Iterator>::Item {
let options = iter.collect::<Vec<_>>();
let count = options.len();
let idx = rng.rand_range(0, (count-1) as u32);
let item = options[idx as usize];
return item;
}
fn main() {
let rng = create_MyRandomNumberGenerator();
let color = get_random_enum(&mut Colors::iter(), rng);
}
This does not compile, as it states that:
error[E0507]: cannot move out of index of `Vec<<T as Iterator>::Item>`
--> stage/main.rs:15:13
|
15 | let item = options[idx as usize];
| ^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `<U as Iterator>::Item`, which does not implement the `Copy` trait
I'm quite new to Rust, but as I understand, <U as Iterator>::Item
does not implement the Copy trait and that's the reason I cannot just return it.
Checking the generated code by the strum macro, I see that Item
is just an alias of my Colors enum, but even if I add the Copy
derive to my enum this still does not work.
I'm quite lost what's the way to implement this in Rust.
答案1
得分: 2
不同于C++,Rust的泛型是有原则的,这意味着它们必须始终对其泛型参数的任何可能实例进行类型检查。因此,不仅需要为具体的结构体/枚举实现Copy
,还需要在泛型类型边界中要求它。即使我们返回了一个.clone()
的Item
实例,仍然需要要求Item
实现Clone
特性。
解决方案:正如编译器提示的那样,我们需要使泛型函数要求迭代器的Item
类型实现Copy
:
fn get_random_enum<T: Iterator<Item=I>, I: Copy>(iter: &mut T, rng: &mut Random) -> I {
let options = iter.collect::<Vec<_>>();
let count = options.len();
let idx = rng.rand_range(0, (count-1) as u32);
let item = options[idx as usize];
return item;
}
英文:
Unlike in C++, Rust generics are principled, meaning that they need to always typecheck for any possible instantiation of their generic parameters. Therefore it does not suffice to implement Copy
for your concrete struct/enum, but you also need to require it in the generic type bound. The same would even be necessary if we returned a .clone()
d instance of the Item
, we would then still need to require the Clone
trait for any Item
.
Solution: As the compiler hints at, we need the generic function to require the Item
type of the iterator to implement Copy
:
fn get_random_enum<T: Iterator<Item=I>, I: Copy>(iter: &mut T, rng: &mut Random) -> I {
let options = iter.collect::<Vec<_>>();
let count = options.len();
let idx = rng.rand_range(0, (count-1) as u32);
let item = options[idx as usize];
return item;
}
答案2
得分: 2
你可以通过这种方式从Vec
中删除所需的项,这样就不必再引入更多的边界:
fn get_random_item<T: Iterator>(iter: &mut T, rng: &mut Random) -> <T as Iterator>::Item {
let mut items = iter.collect::<Vec<_>>();
let count = items.len();
let idx = rng.rand_range(0, (count - 1));
items.swap_remove(idx)
}
如果你的随机生成器实现了rand::Rng
,你也可以直接使用IteratorRandom
扩展特性 来直接选择其中的一个项:
use rand::seq::IteratorRandom;
fn get_random_enum<T: IntoEnumIterator, R: Rng>(rng: &mut R) -> T {
T::iter().choose_stable(rng).unwrap()
}
英文:
You can remove the desired item from that Vec
that way you don't have to introduce any more bounds:
fn get_random_item<T: Iterator>(iter: &mut T, rng: &mut Random) -> <T as Iterator>::Item {
let mut items = iter.collect::<Vec<_>>();
let count = items.len();
let idx = rng.rand_range(0, (count - 1));
items.swap_remove(idx)
}
If your random generator implements rand::Rng
you can also just use the IteratorRandom
extension trait to directly choose on of the items:
use rand::seq::IteratorRandom;
fn get_random_enum<T: IntoEnumIterator, R: Rng>(rng: &mut R) -> T {
T::iter().choose_stable(rng).unwrap()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论