4

Is there any way to deconstruct the array like [a, b] = map so the two array elements are moved into a and b, so that later a and b can be moved into another function (like printme in this case).

enum Direction {
    North,
    East,
    South,
    West,
}

struct RoadPoint {
    direction: Direction,
    index: i32,
}

fn printme(a: RoadPoint, b: RoadPoint) {
    println!("First: {}", a.index);
}

fn main() {
    let mut map: [RoadPoint; 2] = [
        RoadPoint {
            direction: Direction::North,
            index: 0,
        },
        RoadPoint {
            direction: Direction::North,
            index: 0,
        },
    ];

    for i in 1..3 {
        map[i].index = 10;
    }

    //move out
    printme(map[0], map[1])
}
error[E0508]: cannot move out of type `[RoadPoint; 2]`, a non-copy array
  --> src/main.rs:34:13
   |
34 |     printme(map[0], map[1])
   |             ^^^^^^ cannot move out of here

error[E0508]: cannot move out of type `[RoadPoint; 2]`, a non-copy array
  --> src/main.rs:34:21
   |
34 |     printme(map[0], map[1])
   |                     ^^^^^^ cannot move out of here

I'm aware of the fact I could implement the Copy trait, but I actually don't need copy of data in this case. Hence I'm looking for a cleaner solution.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Stefan
  • 381
  • 1
  • 2
  • 4
  • Some of your code is not very idiomatic: prefer direct iteration over collections instead of index ranges (`for point in &mut map { }`). – E_net4 Aug 23 '18 at 13:31

1 Answers1

2

You can get it to work if you use nightly Rust with the non-lexical lifetimes feature and a fixed-length slice pattern:

#![feature(nll)]

enum Direction {
    North,
    East,
    South,
    West,
}

struct RoadPoint {
    direction: Direction,
    index: i32,
}

fn printme(a: RoadPoint, b: RoadPoint) {
    println!("First: {}", a.index);
    println!("Second: {}", b.index);
}

fn main() {
    let map: [RoadPoint; 2] = [
        RoadPoint {
            direction: Direction::North,
            index: 0,
        },
        RoadPoint {
            direction: Direction::North,
            index: 0,
        },
    ];

    let [a, b] = map;
    printme(a, b);
}

Without #![feature(nll)] it fails with:

error[E0382]: use of moved value: `map[..]`
  --> src/main.rs:30:13
   |
30 |     let [a, b] = map;
   |          -  ^ value used here after move
   |          |
   |          value moved here
   |
   = note: move occurs because `map[..]` has type `RoadPoint`, which does not implement the `Copy` trait
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • thanks a lot. that's what I was looking for. – Stefan Aug 23 '18 at 13:35
  • Is there also a workaround for non-nightly versions? Could I recast the pointer in usafe mode ? – Stefan Aug 23 '18 at 13:36
  • Arrays of non `Copy` types in Rust are not very flexible. Maybe you can do something like `let mut v : Vec<_> = (Box::new(map) as Box<[_]>).into(); let b = v.pop().unwrap(); let a = v.pop().unwrap();`. But if you are into that, then you could use a `Vec` instead of an array in the first place! – rodrigo Aug 23 '18 at 13:50
  • thanks a ton! yeah, I might go for a Vec and pop(). This means the data is stored on the heap. Are there any performance implications due to this? – Stefan Aug 23 '18 at 13:55
  • For a stable version, you may look at [split_at](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at) – hellow Aug 23 '18 at 13:57
  • @hellow: But `split_at` applies to slices, not to arrays, that is, they return borrowed references. The OP asks for a way to move values out of the array. – rodrigo Aug 23 '18 at 14:00
  • @Stefan: Sure, there are performance issues. It depends on the length of the array, the size of the stored objects, the usage patterns... if you really care about that you should profile your program. Beware of premature optimizations! – rodrigo Aug 23 '18 at 14:05
  • I suggest moving your good answer to the linked duplicate. – Shepmaster Aug 23 '18 at 14:07
  • @Shepmaster: Done, thanks for the tip. I copied both the _fixed length slice pattern_ and the _boxing array_ solutions. – rodrigo Aug 23 '18 at 14:29