你需要的核心是从数组中获取值而不移动它.两种解决方案是:
使用mem::replace
和mem::uninitialized
用垃圾替换数组中的每个值,获取原始值:
let one = unsafe { mem::replace(&mut v[0], mem::uninitialized()) }; bar(one);
使用ptr::read
离开值在数组中,但得到的所有的值返回:
let two = unsafe { ptr::read(&v[0]) }; bar(two);
这只是在循环中做了几次这样的事情,你很高兴.
只有一个小问题:你看到了unsafe
吗?你猜到了; 在更广泛的情况下,这完全可怕地被打破了:
我们将该数组保留为任意位,仍将被视为a 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); } }
你可以使用数组Option
而不是数组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)); } }