Использование Scala 3.4.2:
Vector(1, 2, 3) match
case Vector() => println("empty")
case _ :+ last => println(s"last: $last")
выдает мне (на мой взгляд неправильное) предупреждение о неисчерпывании
[warn] -- [E029] Pattern Match Exhaustivity Warning: ...
[warn] 5 | Vector(1, 2, 3) match
[warn] | ^^^^^^^^^^^^^^^
[warn] |match may not be exhaustive.
[warn] |
[warn] |It would fail on pattern case: Vector(_, _*), Vector(_, _*), Vector(_, _*), Vector(_, _*), Vector(_, _*), Vector(_, _*)
Если я использую Seq
вместо Vector
, код компилируется нормально.
Похоже, для Scala 3 это то же самое, что обсуждалось для Scala 2 в баге https://github.com/scala/bug/issues/12240.
Кроме того, это может относиться к https://github.com/scala/bug/issues/12252 с пометкой «исправлено в Scala 3».
Мои вопросы:
Специального регистра нет: Vector — это запечатанный признак поэтому компилятор пытается доказать, что совпадение является исчерпывающим, Seq — это просто признак поэтому проверка исчерпываемости вообще не выполняется (поскольку компилятор НЕ проверяет для полноты во всех случаях, только в тех, где это вообще можно доказать).
Развернув вышесказанное: в спецификации 2.13 вы можете прочитать, что только запечатанные гарантированно проверяются на исчерпывающее сопоставление с образцом. Дополнительные проверки можно включить с помощью флагов, но они не включены по умолчанию.
Что касается ошибки, речь идет о проверке полноты unapplySeq
(чтобы компилятор мог проверить, что сопоставление vararg может исчерпать оставшиеся случаи). :+
не зависит от unapplySeq
(с точки зрения компилятора), это другой случай.
Поскольку спецификация Scala 3 еще не выпущена (на самом деле, она все еще находится в разработке), я буду использовать спецификацию Scala 2.13 (спецификация 2.13 + список изменений в Reference является ближайшим приближением спецификации Scala 3, которая у нас на данный момент есть):
Если селектор соответствия шаблону является экземпляром запечатанного класса, компиляция сопоставления шаблонов может выдавать предупреждения, диагностирующие, что данный набор шаблонов не является исчерпывающим, т. е. существует вероятность возникновения MatchError во время выполнения. .
При упоминании исчерпывающих проверок упоминается только sealed
. Во всем остальном поведение не определяется спецификацией, поэтому в лучшем случае оно зависит от реализации.
В примечаниях к выпуску Scala 2.13.4 упоминается -Xlint:strict-unsealed-patmat
флаг, который может добавить более исчерпывающие проверки.
-Xlint
со всеми опциями или если у вас есть что-то вроде sbt-tpolecat, которое включает множество флаговВектор — это запечатанный признак (в версии 2.13 и т. д. в Scala 3, поскольку он использует стандартную библиотеку версии 2.13)
упомянутые вами ошибки связаны с исчерпывающими проверками unapplySeq
, поэтому в основном такие вещи, как:
Vector(1, 2, 3) match
case Vector() => println("empty")
case Vector(multiple*) => println(s"last: ${multiple.last}")
хотя +:
там упоминалось как что-то, что должно быть подвергнуто анализу компилятором, это было скорее желанием - оно НЕ реализовано, и я ожидал, что оно никогда не будет реализовано, потому что это просто произвольное решение.
object :+ {
def unapply[A, CC[_] <: Seq[_], C <: SeqOps[A, CC, C]](t: C with SeqOps[A, CC, C]): Option[(A, C)] = ...
}
Компилятор не может угадать, что это делает внутри и как это связано с другими совпадениями. Кто-то должен был бы добавить в компилятор особый случай... который нельзя было бы добавить ни для одного другого предоставленного пользователем unapply
, поэтому я не ожидаю, что это произойдет.
Собираем все это вместе:
Seq
, компилятор по умолчанию не пытается проверить полноту (с некоторым флагом -X это может быть возможно)Vector
, это sealed
, поэтому он попытается доказать исчерпывающую проверкуunapplySeq
(case Vector(...) =>
)+:
, ни :+
не являются Vector.unapplySeq
, поэтому приведенные выше улучшения их не касаются, и они не исчерпывают никаких возможностей с точки зрения компилятора.
Посмотрите другой вопрос, заданный сегодня: stackoverflow.com/questions/78720251/… - Если он не жалуется на
Seq
, то это либо ошибка, либо странная специальная обработка компилятора только дляSeq
. ИМХО, специальный регистр для компилятора - не очень хорошая идея, либо язык получит надлежащую функцию для определения пользовательских исчерпывающих проверок, в противном случае любое совпадение с шаблоном для чего-то, что не является ADT, должно считаться неисчерпывающим и возможным источником ошибок.