如何一次将值从数组中移出? [英] How do I move values out of an array one at a time?

查看:90
本文介绍了如何一次将值从数组中移出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我拥有一个大小为3的数组,我想对其进行迭代,并在移动时将元素移出.基本上,我想为固定大小的数组实现IntoIterator.

I have ownership of an array of size 3 and I would like to iterate on it, moving the elements out as I go. Basically, I would like to have IntoIterator implemented for a fixed-sized array.

由于数组未在标准库中实现此特征(我理解为什么),是否有解决方法来获得所需的效果?我的对象不是Copy也不是Clone.我可以从数组中创建一个Vec,然后迭代到Vec中,但是我什至不知道该怎么做.

Since arrays don't implement this trait in the standard library (I understand why), is there a workaround to get the desired effect? My objects are not Copy nor Clone. I'd be okay creating a Vec from the array and then iterating into the Vec, but I'm not even sure how to do that.

(有关信息,我想填写 Complete )

(For information, I'd like to fulfill an array of Complete)

这是这种情况的一个简单示例(尝试iter()天真):

Here is a simple example of the situation (with a naive iter() attempt):

// 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

推荐答案

您需要的核心事情是某种在不移动值的情况下从数组中获取值的方法.两种解决方案是:

The core thing you would need is some way of getting the value out of the array without moving it. Two such solutions are:

  1. 使用 mem::replace mem::uninitialized 用垃圾替换数组中的每个值,取回原件:

  1. Use mem::replace and mem::uninitialized to replace each value in the array with garbage, getting the original back:

let one = unsafe { mem::replace(&mut v[0], mem::uninitialized()) };
bar(one);

  • 使用 ptr::read 离开数组中的值,但返回一个拥有的值:

  • Use ptr::read to leave the value in the array but get an owned value back:

    let two = unsafe { ptr::read(&v[0]) };
    bar(two);
    

  • 这只是在循环中执行几次这样的问题,您就可以开始了.

    It's just a matter of doing one of these a few times in a loop and you are good to go.

    只有一个小问题:您看到那些unsafe吗?你猜到了;在更广泛的情况下,这完全是可怕的:

    There's just one tiny problem: you see those unsafe? You guessed it; this is totally, horribly broken in the wider case:

    • 我们将使该数组充满任意位,这些位仍将被视为Foo.在这种情况下,当数组超出范围时不会发生任何特殊情况,因为对于类型Foo没有特殊的Drop实现,但是如果存在,它将访问无效的内存.坏消息!
    • 可以使用 mem::forget 忽略数组并防止其被删除,但是...
    • 如果在将值移出中间(例如,在bar函数内的某处)发生了紧急情况,则数组将处于部分未初始化的状态.这是可以调用Drop实现的另一条(微妙)路径,因此现在我们必须知道数组仍然拥有哪些值以及哪些已移出.我们有责任释放我们仍然拥有的价值,而不是其他价值.
    • 没有什么可以阻止我们意外地访问数组中新无效的值.
    • We are leaving that array full of arbitrary bits that will still be treated like a Foo. In this case, nothing special happens when that array goes out of scope as there's no special Drop implementation for the type Foo, but if there was, it would be accessing invalid memory. Bad news!
    • You could use mem::forget to ignore the array and prevent it from being dropped, but...
    • If a panic happens in the middle of moving the values out (such as somewhere within the bar function), the array will be in a partially-uninitialized state. This is another (subtle) path where the Drop implementation can be called, so now we have to know which values the array still owns and which have been moved out. We are responsible for freeing the values we still own and not the others.
    • Nothing prevents us from accidentally accessing the newly-invalidated values in the array ourselves.

    正确的解决方案是 track 数组中有多少个值有效/无效.删除数组时,可以删除其余的有效项目,而忽略无效的项目.您还必须避免自动析构函数运行.如果我们能够对不同大小的数组进行这项工作,那也将非常好...

    The right solution is to track how many of the values in the array are valid / invalid. When the array is dropped, you can drop the remaining valid items and ignore the invalid ones. You also have to avoid the automatic destructor from running. It'd also be really nice if we could make this work for arrays of different sizes...

    arrayvec 进入的位置.它没有精确的 相同的实现(因为它更聪明),但是它确实具有相同的语义:

    Which is where arrayvec comes in. It doesn't have the exact same implementation (because it's smarter), but it does have the same semantics:

    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);
        }
    }
    


    在每晚的Rust中,您可以使用 std::array::IntoIter 获取按值数组迭代器:


    In nightly Rust, you can use std::array::IntoIter to get a by-value array iterator:

    #![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);
        }
    }
    

    这篇关于如何一次将值从数组中移出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆