Andrew Luhring
Andrew Luhring

Reputation: 1914

How to debug without changing all the function signatures?

I'm learning Rust by reading the book and doing rustlings and watching videos; I think I understand what's happening here, but I don't understand what to do about it.

#[derive(Debug)]
enum Message {
    ChangeColor(u8, u8, u8),
    Echo(String),
    Move(Point),
    Quit,
}

#[derive(Debug)]
struct Point {
    x: u8,
    y: u8,
}

struct State {
    color: (u8, u8, u8),
    position: Point,
    quit: bool,
    message: String,
}

impl State {
    fn change_color(&mut self, color: (u8, u8, u8)) {
        self.color = color;
    }

    fn quit(&mut self) {
        self.quit = true;
    }

    fn echo(&mut self, s: String) {
        self.message = s
    }

    fn move_position(&mut self, p: Point) {
        self.position = p;
    }

    fn process(&mut self, message: Message) {
        println!("{:#?}", &message);
        match message {
            Message::ChangeColor(r, g, b) => self.change_color((r, g, b)),
            Message::Echo(s) => self.echo(s),
            Message::Move(p) => self.move_position(p),
            Message::Quit => self.quit(),
        }

        println!("{:#?}", &message); // <--------
    }
} 

I understand the value of message is being moved on the last line. I appreciate the memory safety of the borrow checker. But I'm just trying to print message to see what happens to it. I know it's being partially moved and I want to witness what it looks like before and after the move.

Without changing the function signatures of everything, how can i just get a look at it?

And also, is the correct thing to do if I wanted to do something else with message just clone it or set it as mutable somehow?

Upvotes: 0

Views: 92

Answers (2)

user4815162342
user4815162342

Reputation: 155406

I want to witness what it looks like before and after the move

This is not possible in safe Rust, and for good reason. It's like saying "I want to witness what my object looks like before and after destructing it" in C++. After a move (in this case partial, but that's beside the point) the value is no longer usable, and attempts to observe it, which would require unsafe code, would be undefined behavior, i.e. cause crashes or miscompilation.

If your actual goal is to observe the object after the match e.g. for logging purposes, you can modify your match not to move from the value. The simplest way to do that is to change match message to match &message and modify the match arms accordingly.

Upvotes: 1

Michael
Michael

Reputation: 394

So there are a couple of things here.

First of all, the signatures should probably be updated a little anyway, the echo function can take impl Into<String> and then call .into() which means we don't have the partial move:

fn echo(&mut self, s: impl Into<String>) {
    self.message = s.into()
}

Message::Echo(ref s) => self.echo(s),

Although this does just clone the value, so the other options is leaving the parameter as String and just cloning s:

Message::Echo(ref s) => self.echo(s.clone()),

Simply calling .clone() might be the best option if you only want some debug code right now. Since you can easily remove it after, and then you don't have redundant cloning.

As for Point, you can derive Clone, Copy, since u8 implements Copy. This means you don't need to move the Point struct:

#[derive(Debug, Copy, Clone)]
struct Point {
    x: u8,
    y: u8,
}

Message::Move(p) => self.move_position(p),

Upvotes: -2

Related Questions