#enums #rust
#перечисления #Ржавчина
Вопрос:
Я хочу сопоставить вариант перечисления, обработать его, а затем передать его дальше. Код должен выглядеть следующим образом:
enum Event {
WindowEvent {
event: WindowEvent,
window_id: usize,
},
}
enum WindowEvent {
Resized(u8),
}
struct Demo {
size: u8,
}
impl Demo {
fn reproduction(amp;mut self, event: Event) {
match event {
e
@
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
self.size = size;
self.handle_event(e);
}
}
}
fn handle_event(amp;self, _event: Event) {}
}
Этот код не проходит проверку заимствования:
error[E0007]: cannot bind by-move with sub-bindings
--> src/lib.rs:18:13
|
18 | / e
19 | | @
20 | | Event::WindowEvent {
21 | | event: WindowEvent::Resized(size),
22 | | ..
23 | | } => {
| |_____________^ binds an already bound by-move value by moving it
error[E0658]: pattern bindings after an `@` are unstable
--> src/lib.rs:21:45
|
21 | event: WindowEvent::Resized(size),
| ^^^^
|
= note: see issue #65490 <https://github.com/rust-lang/rust/issues/65490> for more information
error[E0382]: use of moved value: `event`
--> src/lib.rs:21:45
|
16 | fn reproduction(amp;mut self, event: Event) {
| ----- move occurs because `event` has type `Event`, which does not implement the `Copy` trait
17 | match event {
18 | / e
19 | | @
20 | | Event::WindowEvent {
21 | | event: WindowEvent::Resized(size),
| | ^^^^ value used here after move
22 | | ..
23 | | } => {
| |_____________- value moved here
Я могу полностью разрушить event
и создать его снова при передаче handle_event
, но это кажется неправильным. Зачем мне создавать новый объект, когда я могу передать существующий? Почему я должен заботиться о других полях (их может быть много!), Когда я мог бы использовать подстановочный знак ..
:
match event {
Event::WindowEvent {
event: WindowEvent::Resized(size),
window_id,
} => {
self.size = size;
self.handle_event(Event::WindowEvent {
event: WindowEvent::Resized(size),
window_id,
});
}
}
Я нашел другое решение, которое требует сопоставления дважды:
match event {
e
@
Event::WindowEvent {
event: WindowEvent::Resized(_),
..
} => {
if let Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} = e
{
self.size = size;
}
self.handle_event(e);
}
}
Есть ли лучший способ деструктурировать вариант перечисления без потери исходного значения?
Комментарии:
1. Мне кажется, вашу проблему можно было бы решить, просто написав
self.handle_event(event)
иe
вообще не пытаясь связать. Устраняет ли это проблему? Если нет, нам понадобится больше деталей.2. После попытки заполнить пробелы в вашем коде это работает , поэтому совершенно неясно, в чем проблема.
3. Спасибо! «#! [feature(bindings_after_at)]» — это именно то, что я искал
Ответ №1:
В этом случае повторно event
используйте значение, не пытаясь использовать причудливые методы сопоставления с образцом:
match event {
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
self.size = size;
self.handle_event(event);
}
}
В будущем будет другой вариант. Как указано в сообщениях об ошибках компилятора:
ошибка [E0007]: невозможно выполнить привязку с помощью вложенных привязок
ошибка [E0658]: привязки шаблонов после
@
нестабильныпримечание: для получения дополнительной информации см. Выпуск # 65490
В nightly Rust вы можете добавлять #![feature(bindings_after_at)]
, а затем изменять свой код, чтобы он соответствовал ссылке:
fn reproduction(amp;mut self, event: Event) {
match amp;event {
e
@
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
self.size = *size;
self.handle_event(e);
}
}
}
fn handle_event(amp;self, _event: amp;Event) {}
Если вы сопоставляете перечисления Copy
, вам не нужно будет брать ссылку.