如何为盒装值实现迭代器?
How to implement Iterator for boxed values?
我有一个结构,它通过 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};
}
}
它与 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};
}
}
./numbers.rs:12:25: 12:29 error: cannot move out of borrowed content
./numbers.rs:12 return Some(self.number);
如何正确实现盒装值的迭代器?
这归结为 Rust 的所有权模型以及复制和移动语义之间的区别; Box<T>
具有移动语义,未实现 Copy
,因此 return Some(self.number);
将移动 self.number
,并获得它的所有权;但这是不允许的,因为它需要消耗 self
,这仅由可变引用获取。
你有几个选择(我写“具有移动语义的对象”,我的意思是在这种特定情况下self.number
):
不要return具有移动语义的对象,return其他具有复制语义引用的对象,例如引用而不是装箱值(return引用将要求迭代器对象与被迭代的对象不同,以便您可以在 Item
中写入生命周期;因此它不适用于您的特定用例)或未装箱的数字。
根据具有移动语义的对象构造一个新值到return:
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
}
}
}
使用移动语义克隆对象(这是第二个选项的简化形式,真的):
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
}
}
}
构造一个新值来替换具有移动语义的对象:
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
}
}
}
我有一个结构,它通过 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};
}
}
它与 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};
}
}
./numbers.rs:12:25: 12:29 error: cannot move out of borrowed content
./numbers.rs:12 return Some(self.number);
如何正确实现盒装值的迭代器?
这归结为 Rust 的所有权模型以及复制和移动语义之间的区别; Box<T>
具有移动语义,未实现 Copy
,因此 return Some(self.number);
将移动 self.number
,并获得它的所有权;但这是不允许的,因为它需要消耗 self
,这仅由可变引用获取。
你有几个选择(我写“具有移动语义的对象”,我的意思是在这种特定情况下self.number
):
不要return具有移动语义的对象,return其他具有复制语义引用的对象,例如引用而不是装箱值(return引用将要求迭代器对象与被迭代的对象不同,以便您可以在
Item
中写入生命周期;因此它不适用于您的特定用例)或未装箱的数字。根据具有移动语义的对象构造一个新值到return:
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 } } }
使用移动语义克隆对象(这是第二个选项的简化形式,真的):
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 } } }
构造一个新值来替换具有移动语义的对象:
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 } } }