Вывод типа Scala с обобщениями и ковариацией, возможная проблема в скаляре - PullRequest
2 голосов
/ 21 декабря 2011

У меня есть короткий список вопросов, которые я нашел сегодня. Я новичок в скале, поэтому мои вопросы могут быть тривиальными.

Предположим, у нас есть такой класс:

abstract class A[+T] { def foo[S >: T](x: S): String }

И мы должны предоставить полезный дочерний класс с некоторыми функциями.

1) Моя первая попытка выглядит так:

class B extends A[String] { def foo(x: String) = x }

но компилятор scalac не согласен с сообщением:

xxx@yyy:~$ scalac covariant.scala 
covariant.scala:3: error: class B needs to be abstract, since method foo in class A of type [S >: String](x: S)String is not defined
class B extends A[String] { def foo(x: String) = x }
      ^

Прежде всего, почему scalac не определил параметр универсального типа foo, это действительно сложная задача?

2) Следующая попытка выглядит лучше и должна быть принята, как я думаю:

class B extends A[String] { def foo[String](x: String) = x }

но теперь компилятор широко раскрыл глаза:

covariant.scala:3: error: type mismatch;
 found   : String(in method foo)
 required: java.lang.String
class B extends A[String] { def foo[String](x: String) = x }
                                                         ^

Это похоже на проблему с этим несоответствием String и java.lang.String. Это второй вопрос: действительно ли это ошибка?

3) Наконец, я решил переключить тип String на Date в качестве параметра:

import java.util.Date
class B extends A[Date] { def foo[Date](x: Date) = x.toString }

Он был составлен без каких-либо предупреждений. Итак, последний вопрос: почему? В чем разница между моими вторым и третьим фрагментами?

Кстати, версия скаляка 2.9.1.final

1 Ответ

7 голосов
/ 21 декабря 2011

Действительно, все ваши вопросы проистекают из одного и того же недопонимания.

Вы определили как "класс с параметром типа и метод foo, который может работать с любым типом descended из T , из которого происходит T.

Вы предоставили класс с foo, который может действовать на T, но не обязательно для потомков (на самом деле, поскольку аргументыковариантно, foo на самом деле будет работать с потомками, но спецификация недостаточно точна, чтобы это уловить) суперклассы T.

В двух других вопросах вы случайно повторно использовали имя существующего типа.Когда вы писали foo [Date] или foo [String], вы ссылались не на java.lang.String или java.lang.Date, как вы, очевидно, думали, а на новые типы с тем же именем! Вот почему вы видите несоответствиеString и java.lang.String - это два разных типа.

Попробуйте вместо этого:

abstract class A[+T] { def foo[S >: T](x: S): String }
class B extends A[String] { def foo[S >: String](x: S) = x.toString }

Да, S >: String бессмысленно, так какСтрока является окончательной, но спецификация не можетЯ вырезал все возможные варианты.

ПРИМЕЧАНИЕ Я тоже что-то вроде тирона, поэтому не удивляйтесь, если мой ответ неверен / вводит в заблуждение.И помните: этот совет гарантированно стоит вдвое больше, чем вы заплатили за него или ваши деньги были возвращены.

TOLD YA Большая ошибка: я поменял суперкласс и подкласс.Исправления, сделанные в соответствии с вычеркиванием .

ПРИМЕР ОП не ясно, зачем все это необходимо.Рассмотрим следующую функцию

def foo3(a : A[String]) = a.foo(3)

Это допустимо, потому что 3 (как java.lang.Integer) является примером объекта, который является предком A. Если B.foo были определены как получение String иничего другого, экземпляр B не может быть передан в foo3.

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