Я новичок в Rust из Python. Это мой 4-й день изучения Rust.
После моего первого вопроса Приведение типов для типа Option у меня есть следующий вопрос, связанный с синтаксис match
и концепция владения.
Во-первых, я объявляю структуру ListNode
с реализацией new
.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ListNode {
pub val: i32,
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode {
val
}
}
}
Моя цель - сравнить, одинаковы ли два узла, сравнивая значение узла. Вот моя уродливая реализация.
fn is_same(a: &Option<ListNode>, b: &Option<ListNode>) -> bool {
if a == None && b == None { return true; }
else if a == None && b != None { return false; }
else if a != None && b == None { return false; }
let ca: ListNode = a.clone().unwrap_or(ListNode::new(0));
let cb: ListNode = b.clone().unwrap_or(ListNode::new(0));
if ca.val == cb.val { return true; }
else { return false; }
}
fn main() {
let a: Option<ListNode> = Some(ListNode::new(0));
let b: Option<ListNode> = Some(ListNode::new(0));
println!("{:?}", is_same(&a, &b));
}
Потом у меня было много ошибок ...
no implementation for `&std::option::Option<ListNode> == std::option::Option<_>
Насколько мне известно о концепции владения, использование *
для заимствованного параметра должно быть необязательным. Но, чтобы сравнение работало, мне нужно добавить *
. Ниже доработанная функция работает. (Еще одно обнаруженное заключается в том, что использование a.clone()
нормально, но *a.clone()
неверно с ошибкой type `ListNode` cannot be dereferenced
.)
fn is_same(a: &Option<ListNode>, b: &Option<ListNode>) -> bool {
if *a == None && *b == None { return true; }
else if *a == None && *b != None { return false; }
else if *a != None && *b == None { return false; }
let ca: ListNode = a.clone().unwrap_or(ListNode::new(0));
let cb: ListNode = b.clone().unwrap_or(ListNode::new(0));
if ca.val == cb.val { return true; }
else { return false; }
}
Поскольку приведенный выше код решения слишком уродлив, вот еще одна реализация с использованием match
без избыточных unwrap_or
и *
.
fn is_same(a: &Option<ListNode>, b: &Option<ListNode>) -> bool {
match (a, b) {
(None, None) => true,
(None, _) => false,
(_, None) => false,
(Some(a), Some(b)) => a.val == b.val,
}
}
Это работает отлично, a
и b
успешно сравниваются с None
без *
и unwrap_or
.
Этот код заканчивается вопросами ниже:
- Почему
*
нужно сравнивать с None в моем исходном коде? - В чем магия
match
? Как этот синтаксис заставляет код пропускать использование*
иunwrap_or
для сравнения?
1 ответ
Почему
*
нужно сравнивать сNone
в моем исходном коде?
Само по себе это не необходимо , но Eq
реализовано только для идентичных типов, поэтому вам нужно сравнивать либо два Option<T>
, либо два &Option<T>
. Из этого вы можете увидеть, что сравнивает ваши узлы с &None
тоже сработало бы.
В чем магия матча? Как этот синтаксис заставляет код пропускать использование * и unwrap_or для сравнения?
Match Ergonomics. Обычно match
пытается автоматически добавлять ссылки на шаблоны, чтобы попытаться разрешить типы.
Также я не знаю, заметили ли вы, и просто хотите работать усерднее, но Option<T: Eq>
реализует Eq
, поэтому is_same(&a, &b)
можно было просто написать a == b
.
И еще кое-что, #[inline]
обычно не рекомендуется, как правило, лучше избегать подсказок, если вы специально не посмотрели на сгенерированный вывод, а компилятор не откажется предоставить то, что вы ищете, в противном случае. Имейте в виду: код здесь настолько прост, что в режиме выпуска и даже при использовании сложной версии is_same
с кучей разыменований llvm обнаруживает, что к чему, и просто загружает и форматирует константу true
.
Похожие вопросы
Связанные вопросы
Новые вопросы
rust
Rust - это язык системного программирования без сборщика мусора, ориентированный на три цели: безопасность, скорость и параллелизм. Используйте этот тег для вопросов о коде, написанном на Rust. Используйте тег, относящийся к конкретному изданию, для вопросов, относящихся к коду, для которого требуется определенная редакция, например [rust-2018]. Используйте более конкретные теги для таких подтем, как [rust-cargo] и [rust-macros].