Enum implementing function that mutates itself

Hello fellow rusters! o/
I am experimenting for some with rust lang and got an issue that I cannot beat myself.

Code looks like this:

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

fn turn_left(&mut self) {
    self = match &self {
        Heading::North => Heading::West,
        Heading::West => Heading::South,
        Heading::South => Heading::East,
        Heading::East => Heading::North
    };
}

This Code generates an issue

mismatched types

expected mutable reference, found enum `Heading`

note: expected type `&mut Heading`
     found type `Heading`
help: consider mutably borrowing here: `&mut Heading::West`

After adding '&mut ' in front of every option I got other issue:

cannot assign to immutable argument `self`

cannot assign to immutable argumentrustc(E0384)
main.rs(63, 9): cannot assign to immutable argument

Thw question is, is this even possible?

The help message is a little bit misleading here!

Here's the issue - in your method, self is not the Heading, self is a mutable reference to the Heading. So if you assign to the self variable, you're only replacing that reference, not mutating the underlying object. Generally this isn't something you have to consider in Rust, as it does a lot of auto-dereferencing for you, but this is one case where you need to be explicit.

If you want to de-reference a reference and gain access to the underlying data, you can use the * operator - this makes your code work:

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

impl Heading {
    fn turn_left(&mut self) {
        *self = match self {
            Heading::North => Heading::West,
            Heading::West => Heading::South,
            Heading::South => Heading::East,
            Heading::East => Heading::North,
        };
    }
}

One other thing to note - if you want to replace the data behind a mutable reference but keep hold of the original value, you might run into borrow checker issues. The standard library provides a few functions to help with this, such as std::mem::replace and std::mem::swap. You don't need them here, but it's good to know they exist :slight_smile:

5 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.