Почему сбор с сопоставлением с образцом не может сузить конкретный класс? - PullRequest
0 голосов
/ 27 мая 2018

Давайте рассмотрим следующую черту:

sealed trait AB
case class A(a: Int) extends AB
case class B(b: Int) extends AB

Я пытаюсь collect ограничить коллекцию определенным подклассом.

Если я пытаюсь collect, сопоставляя отдельные компоненты иповторная сборка кортежа:

scala> Seq.empty[(Int, AB)].collect { case (id, a @ A(_))  => (id, a) } : Seq[(Int, A)]
res6: Seq[(Int, ab.A)] = List()

компилятор доволен, но если попытаться вернуть полное совпадение:

scala> Seq.empty[(Int, AB)].collect { case x @ (_, A(_))  => x } : Seq[(Int, A)]

все становится ужасно:

<console>:27: error: type mismatch;
 found   : Seq[(Int, ab.AB)]
 required: Seq[(Int, ab.A)]
       Seq.empty[(Int, AB)].collect { case x @ (_, A(_))  => x } : Seq[(Int, A)]

Почему Scalaкомпилятор не может обработать второй случай?

Ответы [ 3 ]

0 голосов
/ 27 мая 2018

Похоже, это связано с тем, что сопоставление с образцом происходит в нисходящем порядке в подшаблоны, не передавая никакой дополнительной информации из подшаблона в корневой шаблон.

Когда

x @ (_, A(_))

соответствует, все, что x знает о шаблоне, это то, что он имеет ожидаемый тип (Int, AB), и это становится логическим типом x.

Но когда вы присоединяетепеременные шаблона i и a для подшаблона, затем можно извлечь и сохранить более конкретную информацию в предполагаемых типах i и a.В данном конкретном случае с a @ A(_), следующий абзац в спецификации представляется уместным:

Связыватель шаблона x@p состоит из переменной шаблона x и шаблонаp.Тип переменной x является статическим типом T шаблона p.

В случае A(_) статический тип может быть определен как Aпросто взглянув на элемент верхнего уровня шаблона, не возвращаясь в подшаблоны.Следовательно, тип a выводится как A, тип id выводится как Int, следовательно, (id, a) выводится как тип (Int, A).

0 голосов
/ 01 июня 2018

Ваш шаблон кортежа case (_, _) - это просто шаблон конструктора case Tuple2(_, _).

Шаблон конструктора с параметрами типа выводится как case _: Tuple2[x, y].

Ваша переменная будет иметь тип, который выведен, и вы спрашиваете, почему x и y выводят, как они есть.

В раздел о выводе втипизированные шаблоны , он обещает использовать самые слабые ограничения, которые подразумевают соответствие ожидаемому типу.

В этом случае самые слабые ограничения: <: Int и <: AB.

Вкл.с другой стороны, чтобы прояснить тип связанных переменных для сопоставления с образцом, таких как

(Vector.empty: Seq[Nothing]) match { case x @ Nil => x }

, который является не проверкой типа, а проверкой на равенство, и генерирует 2.12, но не 2.13, спецификация теперь говорит :

Тип переменной x - это статический тип T, подразумеваемый шаблоном p.Шаблон p подразумевает тип T, если шаблон соответствует только значениям типа T.

Этот язык может предполагать, что ваша интуиция верна, поскольку, очевидно, (_, A(_)) соответствует толькозначения типа (_, A).Это, кажется, подтверждается определением :

Шаблон соответствует всем объектам, созданным из вызовов конструктора c (v1,…, vn), где каждый шаблон элемента pi соответствует соответствующему значениюvi.

Однако то, что шаблон подразумевает тип, не означает, что тип связанной переменной является самым узким типом, подразумеваемым шаблоном.Что это могло бы означать для Nil примера?

К сожалению, первая форма - - еще не допустимый синтаксис :

case x @ Tuple2[Int @unchecked, A @unchecked](_, A(_)) => x 
case x @ Tuple2(_, A(_)) => x.asInstanceOf[(Int, A)]
0 голосов
/ 27 мая 2018

Поведение указано в Связыватели шаблонов и Шаблоны-конструкторы .

Мне это выглядит так:

  1. Ожидаемый тип шаблона (Int, AB) (в обоих случаях).

  2. В case (id, a @ A(_)) ожидаемый тип A(_) равен AB, но фактический тип равен A.

  3. В case x @ (_, A(_)) тип x является типом шаблона (_, A(_)).Он инстанцируется до Tuple2[Int, AB] , прежде чем заглядывает внутрь на A(_), а затем проверяется только часть A(_) на соответствие: в

    ничего нетclass является полиморфным, тогда его параметры типа создаются так, чтобы создание экземпляра c соответствовало ожидаемому типу шаблона.Созданные экземпляры формальных параметров первичного конструктора c затем принимаются в качестве ожидаемых типов шаблонов компонентов p1,…, pn.Шаблон соответствует всем объектам, созданным из вызовов конструктора c (v1,…, vn), где каждый шаблон элемента pi соответствует соответствующему значению vi.

    , которое будет делать что-либо с фактическими типами p1,…, pn.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...