Ответ 1
Преобразуйте scrutinee в список, чтобы устранить сомнения.
l.toList match {
case Nil => 1
case xs => 2
}
Когда вы снова сопоставляете шаблоны списков, вы можете использовать Nil для проверки пустого списка. Однако, если базовый тип является Iterable, вы все равно можете проверить Nil, и он будет разбит на пустые наборы и т.д. См. Следующий сеанс REPL:
scala> val l: Iterable[Int] = List()
l: Iterable[Int] = List()
scala> l match {
| case Nil => 1
| case _ => 2
| }
res0: Int = 1
scala> val l: Iterable[Int] = Set()
l: Iterable[Int] = Set()
scala> l match {
| case Nil => 1
| case _ => 2
| }
res2: Int = 2
Вопрос: как я могу предотвратить такую проблему? Очевидно, что если l является списком типов, это не ошибка. И если l имеет тип Set, он не будет компилироваться. Но что, если у нас есть класс, который имеет список, определите функцию, которая соответствует шаблону таким образом, а затем кто-то изменит класс, чтобы вместо этого использовать общий итеративный вариант? Является ли этот шаблон Nil vs. _ плохой идеей?
Преобразуйте scrutinee в список, чтобы устранить сомнения.
l.toList match {
case Nil => 1
case xs => 2
}
Одна из возможностей - использовать охрану:
scala> val xs: Iterable[Int] = Set()
xs: Iterable[Int] = Set()
scala> xs match { case xs if xs.isEmpty => 1 case _ => 2 }
res0: Int = 1
Другой способ сделать это - использовать выражение if-else (лучше всего работает, если у вас есть только одно или два условия для проверки):
scala> if (xs.isEmpty) 1 else 2
res1: Int = 1
Вот еще один вариант (каламбур):
scala> val l: Iterable[Int] = List()
l: Iterable[Int] = List()
scala> l.headOption match { case None => 1; case Some(h) => 2 }
res0: Int = 1
Это полезно в случаях, когда вы сопоставляете шаблоны, чтобы получить head
как в популярном List() match { case h :: t => ... }
, но это не список, он Iterable
и ::
не сможет.
Я добавил этот ответ, потому что я подумал, что это довольно часто встречается в шаблоне для коллекции, чтобы получить голову, иначе вы можете просто проверить с помощью xs.isEmpty
.