我拥有大小为3的数组的所有权,我想对其进行迭代,并在移动时将元素移出。基本上,我想为固定大小的数组实现IntoIterator
。
由于数组未在标准库中实现此特征(我理解为什么),是否有解决方法来获得所需的效果?我的对象不是Copy
也不是Clone
。我可以从数组中创建一个Vec
,然后迭代到Vec
中,但是我什至不知道该怎么做。
(有关信息,我想填写Complete
的数组]
这里是一个简单的例子(尝试Complete
天真):
iter()
// No-copy, No-clone struct
#[derive(Debug)]
struct Foo;
// A method that needs an owned Foo
fn bar(foo: Foo) {
println!("{:?}", foo);
}
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
for a in v.iter() {
bar(*a);
}
}
送礼
playground
error[E0507]: cannot move out of borrowed content
--> src/main.rs:14:13
|
14 | bar(*a);
| ^^ cannot move out of borrowed content
和mem::replace
将数组中的每个值替换为垃圾,取回原始值:mem::replace
使用mem::uninitialized
将值保留在数组中,但又返回一个拥有的值:
mem::uninitialized
只需在循环中几次执行其中之一,您就可以进行了。
只有一个小问题:您看到那些let one = unsafe { mem::replace(&mut v[0], mem::uninitialized()) }; bar(one);
吗?你猜到了;在更广泛的情况下,这是完全可怕的:我们将使该数组充满任意位,仍然将其视为
ptr::read
。在
ptr::read
没有特殊的let two = unsafe { ptr::read(&v[0]) };
bar(two);
实现,但是如果存在,它将访问无效的内存。坏消息! unsafe
忽略该数组并防止其被删除,但是...Foo
函数中的某处)时发生了紧急情况,则该数组将处于部分未初始化的状态。这是可以调用Drop
实现的另一条(微妙)路径,因此现在我们必须知道数组仍拥有哪些值以及哪些已移出。我们有责任释放我们仍然拥有的价值,而不是其他价值。 Foo
出现的位置。它没有exact相同的实现(因为它更聪明),但是它具有相同的语义:
mem::forget
在每晚的Rust中,您可以使用
mem::forget
获得按值数组迭代器:
bar
std::array::IntoIter
nightly中使用)和定长切片模式,您可以移出数组:
#![feature(array_value_iter)]
use std::array::IntoIter;
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
for a in IntoIter::new(v) {
bar(a);
}
}
但是,如果阵列很大,此解决方案将无法很好地扩展。另一种选择,如果您不介意额外的分配,则将数组装箱并将其转换为Option<Foo>
:
Foo
如果数组很大,那可能是个问题。但是,如果数组很大,则您不应该首先在堆栈中创建它!