Return value witouth copy trait

fn intersect_which_side(&self, r2: &Rect) -> Side {
        let side_intersect_lengths = [
            (Side::Top, self.intersect_length(&r2, Side::Top)),
            (Side::Bottom, self.intersect_length(&r2, Side::Bottom)),
            (Side::Left, self.intersect_length(&r2, Side::Left)),
            (Side::Right, self.intersect_length(&r2, Side::Right)),
        ];

        let mut min = &side_intersect_lengths[0];
        for s in &side_intersect_lengths {
            if s.1 < min.1 {
                min = s
            }
        }

        min.0
    }
error[E0507]: cannot move out of `min.0` which is behind a shared reference
  --> src/main.rs:60:9
   |
60 |         min.0
   |         ^^^^^ move occurs because `min.0` has type `Side`, which does not implement the `Copy` trait

Is there a way to return that value without a implementing a copy trait

I see 3 possible alternatives:

  1. In some cases it might be possible to return a borrow to the value, rather than the value itself
  2. Add a Clone impl for the type of the value you want returned, and return min.0.clone()
  3. Wrap the value in an Arc/Rc, and clone that rather than the value.

You could do something like this:

fn intersect_which_side(r2: &Rect) -> Side {
    [
        (Side::Top, intersect_length2(r2, Side::Top)),
        (Side::Bottom, intersect_length2(r2, Side::Bottom)),
        (Side::Left, intersect_length2(r2, Side::Left)),
        (Side::Right, intersect_length2(r2, Side::Right)),
    ]
    .into_iter()
    .reduce(|a, b| if a.1 < b.1 { a } else { b })
    .unwrap()
    .0
}

Can I ask why you don't want to implement Copy for the Side enum? It looks like it is just a list of variant names with no data. So implementing Copy is as simple as adding #[derive(Copy, Clone)] above the enum.

If you're not familiar with Copy, the general rule is: types that can implement Copy, should implement Copy. Also see When can my type be Copy?.

3 Likes

The link is self-descripting, or is this a mistake?

1 Like

Yes, it is self describing. I just wanted to point out where it is documented. Is there a better way to do this? I'm happy to change it.

They meant it links to your comment :slightly_smiling_face:

1 Like

Oh! I'll fix it. Thanks @Cerber-Ursi and @quinedot.

I went with #[derive(Clone,Copy)] but i wanted to know if there was another solution in case the same situation repeats but with a more complex structure.

The reply from jjpe gives you a good overview of different options in cases where you can't implement Copy.

The most common thing to do, especially while learning Rust, is to use Clone. When a non-Copy field of a data structure is owned by that data structure, you can't normally move it out of the data structure. If the type implements Clone, you can clone it to make a new owned value by duplicating the value safely. Cloning can be expensive, but it depends on the type. Many common types like String implement Clone and you can implement Clone for your own types.

Other alternatives depend on the situation. In addition to what jjpe listed, there are cases where you can move a non-Copy owned value out of a data structure. For example, if the value is contained in an Option you can use Option::take to replace the value in the data structure with a None value.

    fn intersect_which_side(&self, r2: &Rect) -> Side {
        Side::iter() // https://docs.rs/strum/latest/strum/derive.EnumIter.html
            .min_by_key(|&side| self.intersect_length(r2, side)
            .unwrap()
    }
1 Like