Я изучаю Rust, читая книгу, занимаясь шорохами и просматривая видео; Кажется, я понимаю, что здесь происходит, но не понимаю, что с этим делать.
#[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); // <--------
}
}
Я понимаю, что значение сообщения перемещается в последнюю строку. Я ценю безопасность памяти средства проверки заимствований. Но я просто пытаюсь распечатать сообщение, чтобы посмотреть, что с ним произойдет. Я знаю, что его частично перемещают, и хочу увидеть, как он выглядит до и после перемещения.
Не меняя сигнатуры функций всего, как я могу просто взглянуть на это?
И также, правильно ли поступить, если я хочу сделать что-то еще с сообщением, просто клонировать его или каким-то образом сделать его изменяемым?
состояние определенно меняется, но сообщение перемещается. Меня смущает, что делать с чем-то после того, как оно было перемещено. И действительно, если в целом есть лучший способ отладки или просмотра значений, потому что иногда printlns по какой-то причине даже не печатает на терминал
message
перемещается в выражении match
, а не в последнюю строку. Вы пытаетесь распечатать message
после его употребления. В этот момент все прошло. Возможно, он частично освобожден. Вы просто не сможете распечатать его после того, как оно исчезнет, и я не понимаю, зачем вам это нужно.
После того, как что-то было перемещено, вы не можете делать ничего, кроме перемещенной области. Если вы хотите отладить, вы можете использовать макрос dbg!
. Если вы хотите отладить состояние, я могу дать ответ.
Я хочу увидеть, как он выглядит до и после перемещения — это все равно, что сказать: «Я хочу увидеть, как выглядит мой объект до и после free()». Управление памятью работает не так — после освобождения (в данном случае частичного, но это не имеет значения) объект становится непригоден для использования. Кроме того, вы даже не меняете объект, поэтому даже если бы вы могли каким-то образом распечатать его после перемещения, вы бы получили то же самое. Если вы хотите, чтобы значение оставалось пригодным для использования, измените match message
на match &message
и соответствующим образом измените соответствующие рычаги.
Если вы получаете доступ к перенесенному значению, вы обязательно должны делать это небезопасным способом (см., например, std::mem::transmute
, который позволит вам создать ссылку, пережившую перенесенное значение). Если вы сделаете это, ваша программа потенциально может выйти из строя. Но, вероятно, в этом случае значение не будет отличаться во второй точке, потому что переход от значения - это концепция времени компиляции - во время выполнения значение просто удаляется в конце своей области действия, как обычно, что здесь является концом область действия функции.
@user2407038 user2407038 Но компилятор может использовать информацию о живучести (т. е. перемещении), чтобы переменные перекрывались (потенциально).
@ChayimFriedman Действительно, компилятор имеет большую свободу в выборе того, когда и как он удаляется. Он не указан, поскольку не существует стандарта для его указания, и он может даже отличаться в разных версиях компилятора. Но это именно то, что надеется наблюдать ФП: «Я хочу увидеть, как это выглядит до и после переезда». Здесь «оно» — это ячейка памяти, ранее занятая message
.
@user4815162342 user4815162342 это правильный ответ (совпадение и сообщение), если вы хотите, чтобы он был помечен как ответ, сделайте его и я отмечу его как решенный
@AndrewLhring Готово. Рад, что ваша проблема решена!
Итак, здесь есть пара вещей.
Прежде всего, подписи, вероятно, все равно следует немного обновить, функция echo
может принять impl Into<String>
, а затем вызвать .into()
, что означает, что у нас нет частичного перемещения:
fn echo(&mut self, s: impl Into<String>) {
self.message = s.into()
}
Message::Echo(ref s) => self.echo(s),
Хотя это просто клонирует значение, поэтому другие варианты оставляют параметр как String
и просто клонируют s
:
Message::Echo(ref s) => self.echo(s.clone()),
Просто вызов .clone()
может быть лучшим вариантом, если прямо сейчас вам нужен только отладочный код. Так как вы можете легко удалить его после, и тогда у вас не будет избыточного клонирования.
Что касается Point
, вы можете вывести Clone, Copy
, поскольку u8
реализует Copy
. Это означает, что вам не нужна move
структура Point
:
#[derive(Debug, Copy, Clone)]
struct Point {
x: u8,
y: u8,
}
Message::Move(p) => self.move_position(p),
Я хочу увидеть, как это выглядит до и после переезда.
В безопасном Rust это невозможно, и на то есть веские причины. Это все равно что сказать: «Я хочу увидеть, как будет выглядеть мой объект до и после его разрушения» на C++. После перемещения (в данном случае частичного, но это не имеет значения) значение больше невозможно использовать, и попытки его наблюдения, для чего потребуется небезопасный код, будут неопределенным поведением, т. е. вызовут сбои или неправильную компиляцию.
Если ваша реальная цель — наблюдать за объектом после match
, например. для целей ведения журнала вы можете изменить свой match
, чтобы он не отклонялся от значения. Самый простой способ сделать это — заменить match message
на match &message
и соответствующим образом изменить соответствующие плечи.
Меняется
State
неMessage
. Так может быть, вместо этого вы хотели отладитьState
? Если вы хотите проверить сообщение, вы можете добавитьClone
к производному, а затем использоватьmessage.clone()
в условииmatch
.