我拥有一个3号数组的所有权,我想迭代它,随着我的去向移动元素.基本上,我想IntoIterator
实现一个固定大小的数组.
由于数组没有在标准库中实现这个特性(我理解为什么),是否有解决方法来获得所需的效果?我的对象不是Copy
也不是Clone
.我可以Vec
从数组中创建一个然后迭代进入Vec
,但我甚至不确定如何做到这一点.
(有关信息,我想完成一系列的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);
}
}
Run Code Online (Sandbox Code Playgroud)
给
error[E0507]: cannot move out of borrowed content
--> src/main.rs:14:13
|
14 | bar(*a);
| ^^ cannot move out of borrowed content
Run Code Online (Sandbox Code Playgroud)
She*_*ter 10
你需要的核心是从数组中获取值而不移动它.两种解决方案是:
使用mem::replace
和mem::uninitialized
用垃圾替换数组中的每个值,获取原始值:
let one = unsafe { mem::replace(&mut v[0], mem::uninitialized()) };
bar(one);
Run Code Online (Sandbox Code Playgroud)使用ptr::read
离开值在数组中,但得到的所有的值返回:
let two = unsafe { ptr::read(&v[0]) };
bar(two);
Run Code Online (Sandbox Code Playgroud)这只是在循环中做了几次这样的事情,你很高兴.
只有一个小问题:你看到了unsafe
吗?你猜到了; 在更广泛的情况下,这完全可怕地被打破了:
Foo
.在这种情况下,当该数组超出范围时没有什么特别的事情发生,Drop
因为该类型没有特殊的实现Foo
,但如果存在,则会访问无效的内存.坏消息!mem::forget
忽略该数组并防止它被删除,但......bar
函数内某处)的过程中发生恐慌,则阵列将处于部分未初始化状态.这是Drop
可以调用实现的另一个(微妙的)路径,所以现在我们必须知道数组仍然拥有哪些值以及哪些值已被移出.我们有责任释放我们仍然拥有的价值而不是其他价值观.正确的解决方案是跟踪数组中有多少值有效/无效.删除数组后,您可以删除剩余的有效项并忽略无效项.您还必须避免自动析构函数运行.如果我们能够为不同大小的阵列做这项工作,那也真的很好......
这是arrayvec的用武之地.它没有完全相同的实现(因为它更聪明),但它确实具有相同的语义:
extern crate arrayvec;
use arrayvec::ArrayVec;
#[derive(Debug)]
struct Foo;
fn bar(foo: Foo) {
println!("{:?}", foo)
}
fn main() {
let v = ArrayVec::from([Foo, Foo, Foo]);
for f in v {
bar(f);
}
}
Run Code Online (Sandbox Code Playgroud)
你可以使用数组Option<Foo>
而不是数组Foo
.当然它有一些记忆惩罚.函数take()
替换数组中的值None
.
#[derive(Debug)]
struct Foo;
// A method that needs an owned Foo
fn bar(foo: Foo) { println!("{:?}", foo); }
fn main() {
let mut v = [Some(Foo),Some(Foo),Some(Foo)];
for a in &mut v {
a.take().map(|x| bar(x));
}
}
Run Code Online (Sandbox Code Playgroud)
使用非词法生命周期功能(自Rust 1.31.0起可用)和固定长度切片模式(自Rust 1.26.0起可用),您可以移出数组:
#[derive(Debug)]
struct Foo;
fn bar(foo: Foo) {
println!("{:?}", foo);
}
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
let [a, b, c] = v;
bar(a);
bar(b);
bar(c);
}
Run Code Online (Sandbox Code Playgroud)
然而,如果数组很大,这个解决方案就不能很好地扩展。
如果您不介意额外的分配,另一种选择是将数组装箱并将其转换为Vec
:
fn main() {
let v: [Foo; 3] = [Foo, Foo, Foo];
let v = Vec::from(Box::new(v) as Box<[_]>);
for a in v {
bar(a);
}
}
Run Code Online (Sandbox Code Playgroud)
如果数组很大,这可能是一个问题。但是,如果数组非常大,那么您就不应该首先在堆栈中创建它!
归档时间: |
|
查看次数: |
1962 次 |
最近记录: |