我有一个结构,通过next特征从方法给出数字Iterator:
struct Numbers{
number: usize,
count: usize
}
impl Iterator for Numbers {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
self.count -= 1;
return Some(self.number);
}
return None;
}
}
fn main(){
let numbers = Numbers{
number: 777,
count: 10
};
for n in numbers {
println!{"{:?}", n};
}
}
Run Code Online (Sandbox Code Playgroud)
它适用于usize类型.但是Box类型的相同代码会产生编译错误:
struct Numbers{
number: Box<usize>,
count: usize
}
impl Iterator for Numbers {
type Item = Box<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
self.count -= 1;
return Some(self.number);
}
return None;
}
}
fn main(){
let numbers = Numbers{
number: Box::new(777),
count: 10
};
for n in numbers {
println!{"{:?}", n};
}
}
Run Code Online (Sandbox Code Playgroud)
./numbers.rs:12:25:12:29错误:无法搬出借来的内容
./numbers.rs:12返回一些(self.number);
如何正确实现盒装值的迭代器?
这归结为Rust的所有权模型以及复制和移动语义之间的区别; Box<T>有移动语义,没有实现Copy,所以return Some(self.number);会移动self.number,取得它的所有权; 但这是不允许的,因为它需要消耗self,这只能通过可变引用来实现.
你有几个选择(在那里我写"带有移动语义的对象",我的意思是在这个特定情况下self.number):
不要使用移动语义返回对象,使用复制语义引用返回其他内容,例如引用而不是盒装值(返回引用将要求迭代器对象与要迭代的对象不同,以便您可以编写生命周期Item;因此它不适用于您的特定用例)或未装箱的数字.
构造一个基于具有移动语义的对象返回的新值:
impl Iterator for Numbers {
type Item = Box<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
self.count -= 1;
Some(Box::new(self.number))
} else {
None
}
}
}
Run Code Online (Sandbox Code Playgroud)用移动语义克隆对象(这是第二个选项的简化形式,真的):
impl Iterator for Numbers {
type Item = Box<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
self.count -= 1;
Some(self.number.clone())
} else {
None
}
}
}
Run Code Online (Sandbox Code Playgroud)构造一个新值来代替具有移动语义的对象:
use std::mem;
impl Iterator for Numbers {
type Item = Box<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
self.count -= 1;
let number = mem::replace(&mut self.number, Box::new(0));
// self.number now contains 0
Some(number)
} else {
None
}
}
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |