我拥有一个大小为3的数组的所有权,我想在它上面进行迭代,随着我的操作将元素移出。基本上,我想为一个固定大小的数组实现IntoIterator
。
既然数组在标准库中没有实现这个特性(我知道为什么),有没有一个变通的方法来获得想要的效果?我的对象既不是Copy
,也不是Clone
。我可以从数组中创建一个Vec
,然后迭代到Vec
中,但我甚至不知道如何做到这一点。
(For信息,我想实现一个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);
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:14:13
|
14 | bar(*a);
| ^^ cannot move out of borrowed content
4条答案
按热度按时间wrrgggsh1#
Rust 2021(可从Rust 1.56获得)
可以使用for循环迭代数组:
生 rust 1.51
你可以使用
std::array::IntoIter
来获得一个按值数组迭代器:以前的Rust版本
你所需要的核心东西是某种方法,在不移动数组的情况下,从数组中取出值。
可以使用
mem::transmute
将数组转换为mem::MaybeUninit
数组,然后使用ptr::read
将值保留在数组中,但返回一个拥有的值:这只是一个问题,这样做几次在一个循环,你是好去。
只有一个小问题:你看到
unsafe
了吗?你猜对了在更广泛的情况下,这是完全的,可怕的破坏:MaybeUninit
时不执行任何操作;这可能导致内存泄漏。bar
函数中的某个地方)发生了混乱,数组将处于部分未初始化的状态。这是另一个(微妙的)可以删除MaybeUninit
的路径,所以现在我们必须知道数组仍然拥有哪些值,哪些值已经移出。我们负责释放我们仍然拥有的值,而不是其他值。正确的解决方案是 * 跟踪 * 数组中有多少值是有效/无效的。当数组被删除时,您可以删除剩余的有效项并忽略无效项。如果我们可以使此方法适用于不同大小的数组,那就太好了...
这就是arrayvec的用武之地。它没有 * 完全 * 相同的实现(因为它更智能),但它有相同的语义:
r6l8ljro2#
您可以使用
Option<Foo>
数组代替Foo
数组。当然,这会造成一些内存损失。函数take()
将数组中的值替换为None
。mftmpeh83#
使用non-lexical lifetimes feature(从Rust 1.31.0开始可用)和 * 固定长度的切片模式 *(从Rust 1.26.0开始可用),您可以从数组中移出:
但是,如果阵列很大,则此解决方案不能很好地扩展。
如果您不介意额外的分配,另一种方法是将数组装箱并将其转换为
Vec
:如果数组非常大,这可能是个问题。但是,如果数组非常大,那么首先就不应该在堆栈中创建它!
gcuhipw94#
自生 rust 1.65起稳定
这是
LendingIterator
的开发用例: