Это запрещено спец.См. 3.2.7 Составные типы .
В объявлении метода в структурном определении тип любого параметра значения может ссылаться только на параметры типа или абстрактные типы, которые содержатся внутриуточнение.То есть он должен ссылаться либо на параметр типа самого метода, либо на определение типа в пределах определения.Это ограничение не относится к типу результата функции.
До исправления Ошибка 1906 компилятор скомпилировал бы это, и вы получили бы метод, не найденный во время выполнения,Это было исправлено в ревизии 19442 , и именно поэтому вы получаете это замечательное сообщение.
Тогда возникает вопрос, почему это не разрешено?
Здесь очень подробное объяснение от Жиля Дубоче из списка рассылки scala в 2007 году. Это примерно сводится к тому, что структурные типы используют отражение, и компилятор не знает, как искать вызываемый метод, если он использует определенный типза пределами уточнения (компилятор не знает заранее, как заполнить второй параметр getMethod в p.getClass.getMethod("pimp", Array(?))
Но посмотрите на пост, он ответит на ваш вопрос и некоторыеподробнее.
Редактировать:
Список приветствий.
Я пытаюсь определить структурные типы с абстрактным типом данных в параметре функции. ... Любая причина?
В последнее время я слышал о двух вопросах, касающихся расширения структурной типизации Scala 2.6, и я хотел бы ответить на них здесь.
- Почему мы изменили ScalСобственные значения ("int" и т. д.) упаковывают схему в Java ("java.lang.Integer").
- Почему существуют ограничения на параметры для структурно определенных методов («Тип параметра в структурном уточнении может необратитесь к абстрактному типу, определенному вне этого же уточнения »).
Прежде чем я смогу ответить на эти два вопроса, мне нужно поговорить о реализации структурных типов.
Тип JVMСистема очень проста (и соответствует Java 1.4).Это означает, что многие типы, которые могут быть представлены в Scala, не могут быть представлены в ВМ.Зависимые от пути типы («xyA»), одноэлементные типы («a.type»), составные типы («A с B») или абстрактные типы - это все типы, которые не могут быть представлены в системе типов JVM.
Чтобы иметь возможность компилировать в байт-код JVM, компиляторы Scala изменяют типы программы Scala на «стирание» (см. Раздел 3.6 справки).Стираемые типы могут быть представлены в системе типов ВМ и определяют дисциплину типов в программе, которая эквивалентна дисциплине программы, типизированной типами Scala (с сохранением некоторых приведений), хотя и менее точной.В качестве примечания, тот факт, что типы стираются в ВМ, объясняет, почему операции с динамическим представлением типов (сопоставление с образцом в типах) очень ограничены по отношению к системе типов Scala.
До сих пор все конструкции типовв Скале можно было как-то стереть.Это не верно для структурных типов.Простой структурный тип «{def x: Int}» нельзя стереть в «Object», так как виртуальная машина не позволяет получить доступ к полю «x».Использование интерфейса «interface X {int x {};} », Так как стертый тип также не будет работать, потому что любой экземпляр, связанный со значением этого типа, должен будет реализовать этот интерфейс, что невозможно сделать при наличии отдельной компиляции.В самом деле (смиритесь со мной) любой класс, который содержит член с тем же именем, что и член, определенный в структурном типе, где угодно, должен был бы реализовать соответствующий интерфейс.К сожалению, этот класс может быть определен еще до того, как станет известно о существовании структурного типа.
Вместо этого любая ссылка на структурно определенный член реализована как рефлексивный вызов, полностью обходя систему типов виртуальной машины.Например, def f(p: { def x(q: Int): Int }) = p.x(4)
будет переписано примерно так:
def f(p: Object) = p.getClass.getMethod("x", Array(Int)).invoke(p, Array(4))
А теперь ответы.
- “invoke »будет использовать значения в штучной упаковке (« java.lang.Integer ») всякий раз, когда
В вызываемом методе используются собственные значения («int»). Это означает, что выше
вызов должен действительно выглядеть как «... invoke (p, Array (new
java.lang.Integer (4))). intValue».
Целочисленные значения в программе Scala уже часто заключаются в квадрат (чтобы
«Любой» тип), и было бы расточительно распаковать их из собственного Скала
Схема бокса, чтобы сразу перезаписать их как java.lang.Integer.
Хуже всего, когда отражающий вызов имеет тип возврата «Любой»,
Что делать, когда возвращается java.lang.Integer? Называется
метод может либо возвращать «int» (в этом случае он должен быть
распакован и перезаписан как ящик Scala) или он может возвращать
java.lang.Integer, который следует оставить нетронутым.
Вместо этого мы решили изменить собственную схему бокса в Scala на Java.
две предыдущие проблемы просто исчезают. Некоторые связанные с производительностью
Оптимизации, которые мы имели с боксерской схемой Скала (предварительно рассчитать
в штучной форме наиболее распространенных чисел) были просты в использовании с Java
бокс тоже. В конце концов, использование Java-бокса было даже немного быстрее, чем
наша собственная схема.
- Второй параметр «getMethod» - это массив с типами
параметры (структурно определенного) метода для поиска - для
выбрать, какой метод получить, когда имя перегружено. Это
одно место, где необходимы точные статические типы в процессе
перевод вызова структурного члена. Обычно эксплуатируемые статические типы
для параметра метода предоставляется структурный тип
определение. В приведенном выше примере тип параметра «x» известен как
быть «Int», что позволяет искать его.
Типы параметров, определенные как абстрактные типы, где абстрактный тип
определены внутри объема структурной обработки не проблема
или:
def f (p: {def x [T] (t: T): Int}) = p.xInt
В этом примере мы знаем, что любой экземпляр, переданный в «f» как «p», будет
определить «x [T] (t: T)», которое обязательно стирается в «x (t: Object)».
поиск выполняется правильно для стертого типа:
def f (p: Object) = p.getClass.getMethod ("x", Array (Object)). invoke (p,
Array (новый java.lang.Integer (4)))
Но если абстрактный тип за пределами области структурного уточнения
используется для определения параметра структурного метода, все ломается:
def f [T] (p: {def x (t: T): Int}, t: T) = p.x (t)
Когда вызывается «f», «T» может быть создан для любого типа, например:
f [Int] ({def x (t: Int) = t}, 4)
f [Any] ({def x (t: Any) = 5}, 4)
Поиск для первого случая должен быть «getMethod (« x »,
Array (int)) »и для второго« getMethod («x», Array (Object)) », и
нет способа узнать, какой из них генерировать в теле
«F»: «p.x (t)».
Чтобы разрешить определение уникального вызова «getMethod» внутри тела «f» для
любое создание экземпляра «T» потребовало бы передачи любого объекта в «f» в качестве
Параметр «p» стирает тип «t» в «Любой». Это было бы
преобразование, где тип членов класса зависит от того, как
экземпляры этого класса используются в программе. А это что то
мы определенно не хотим делать (и не может быть сделано с отдельным
сборник).
В качестве альтернативы, если Scala поддерживает типы времени выполнения, их можно использовать для
решить эту проблему. Может быть, однажды ...
Но пока, используя абстрактные типы для параметра структурного метода
типы просто запрещены.
С уважением,
Жиль.