Краткий ответ: в соответствии со спецификациями Scala вам не нужно определять метод 'filter' для примера, который вы привели, но есть open bug , что означает, что в данный момент это требуется.
Длинный ответ: алгоритм десагеринга, применяемый для понимания, описан в спецификации языка Scala . Давайте начнем с раздела 6.19 «Для пониманий и циклов» (я смотрю на версию 2.9 спецификации):
На первом этапе каждый генератор p <- e, где p не является неопровержимым (§8.1) для типа e, заменяется на p <- e.withFilter {case p => true; case _ => false}
Важным моментом для вашего вопроса является то, является ли модель в понимании «неопровержимой» для данного выражения или нет. (Шаблон - это бит перед «<-»; выражение - это бит после.) Если он «неопровержим», то withFilter не будет добавлен, в противном случае он будет необходим. </p>
Хорошо, но что значит "неопровержимый"? Перейдите к разделу 8.1.14 спецификации («Неопровержимые образцы»). Грубо говоря, если компилятор может доказать, что шаблон не может потерпеть неудачу при сопоставлении выражения, то шаблон неопровержим и вызов withFilter не будет добавлен.
Теперь ваш пример, который работает должным образом, - это первый тип неопровержимого шаблона из раздела 8.1.14, шаблон переменной. Таким образом, первый пример позволяет компилятору легко определить, что withFilter
не требуется.
Ваш второй пример потенциально является третьим типом неопровержимого паттерна, паттерном конструктора. Попытка сопоставить (k, v), который равен Tuple2[Any,Any]
с Tuple2[Int,Int]
(см. Раздел 8.1.6 и 8.1.7 из спецификации)), успешна, поскольку Int
неопровержимо для Any
. Поэтому второй шаблон также неопровержим и не нуждается (не должен) в методе withFilter
.
В примере Даниэля Tuple2[Any,Any]
не является неопровержимым против Any
, поэтому добавляются вызовы withFilter.
Кстати, в сообщении об ошибке говорится о методе filter
, но в спецификации говорится о withFilter
- он был изменен в Scala 2.8, см. этот вопрос и ответ для подробностей. 1035 *