Help: Clone not found... but exists


#1

Hi, I’m trying to learn rust. Just when I think I’ve got the hang of ownership, I’m proved wrong.

Here’s a playground link to my current problem: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=ef5c29a9ebac24d0ec5f87cd4c1e77a9 .

    86 |         for block in self.active_piece.unwrap().blocks.iter() {
       |                      ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content

As per my understanding, active_piece is borrowed and since unwrap consumes, this code is invalid.

Thus, I send unwrap a cloned copy…

86 | for block in self.active_piece.clone().unwrap().blocks.iter() {

This throws a 'Clone not found … but exists error… ’ error. What am I doing wrong?


#2

What happens if active_piece is None? That’s why it’s more common in rust to use pattern matching to resolve Options and Results. Take a look at this modified program where I use

if let Some(piece) = self.active_piece {

This is a pretty neat part of rust called pattern matching, and it’s very useful in rust.

As to why your original attempt to solve it didn’t work:
active_piece is an Option<Piece>, meaning that the Option will only have a clone function if its contents are Clone as well. Piece isn’t clone, and could be modified like so to be Clone

#[derive(Clone)]
struct Piece {
    blocks: Vec<Block>,
}

But then you’d need Block to be Clone as well, so you could write

#[derive(Clone)]
struct Block {
    x: u8,
    y: u8,
}

But pattern matching is faster because you don’t unnecessarily clone information.


#3

Ahh, makes sense. I (wrongly) thought of pattern matching as just that, a construct to match patterns. Didn’t think of them as something that could extract as well. It’s a lot more clear now. Thanks for the quick help. I appreciate it. @OptimisticPeach :smiley:


#4

Oh, I made an error, if you use

if let Some(piece) = self.active_piece

Then you’ll still be consuming it. In the playground example, I did it correctly and specified &self.active_piece which is the equivalent of

if let Some(ref piece) = self.active_piece

#5

ref patterns are not deprecated, as far as I know.


#6

Perhaps not “deprecated” per say, but I thought that it had been “replaced” by if let Some(_) = &something and therefore it was proffered to write new code as that instead of

if let Some(ref _) = something)

#7

Definitely not deprecated. There are lots of situations left where match ergonomics doesn’t kick in and you need it.


#8

This is perhaps the most common question I see in IRC; kudos for getting to that realization!

The fix is usually Option::as_ref:

for block in self.active_piece.as_ref().unwrap().blocks.iter() {

That turns your &Option<T> into a new Option<&T> that can be moved into the unwrap fine.