2016-08-31 13 views
0

Позвольте мне сразу перейти к проблеме, с которой я столкнулся, когда висит вокруг с ограничениями типа.
Рассмотрим следующее ... Я создал функцию 'Foo' как этотПодтипирование ведет к Any: ошибка в компиляторе или проблема с моим кодом?

def foo[A,B](x:A,y:B):(A,B)=(x,y) 

Я вызывается Foo в листе лестницу, как

foo("Mars",2400) 

я получил результат, как

res0: (String, Int) = (Mars,2400) 

Обратите внимание на допустимые типы Марса и 2400
Теперь я хотел обеспечить, чтобы функция «foo» принимала целые числа или плавающие или двойные (любой тип, который является подтипом AnyVal).

Для исполнения я написал код, как

def fooNew[A<:B,B](x:A,y:B):(A,B)=(x,y) 

выведенных типов из предыдущего кода был (String, Int), и когда я ссылаться fooNew как

fooNew("Saturn",2400) 

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

res0: (String, Any) = (Saturn,2400) 

Теперь, желаемый способ enfor cing здесь не работал. Если бы я сделал что-то вроде этого

def fooNew[A<:B,B<:AnyVal](x:A,y:B):(A,B)=(x,y) 

Компилятор наверняка принес бы ошибку для меня, и это произошло!

Error:(2, 2) inferred type arguments [String,Any] do not conform to method fooNew's type parameter bounds [A <: B,B <: AnyVal] 
fooNew("Saturn",2400);} 

Я хочу спросить, почему не компилятор типа, как Int вместо этого выводится тип Любой и пусть мой код проходит проверку типа?
Должен ли я всегда применять второй тип, чтобы быть подтипом AnyVal вместо того, чтобы дать компилятору сделать его для меня? или это ошибка в компиляторе.
Ищите помилование, если вы обнаружили, что мой вопрос вводит в заблуждение или не соответствует вашим ожиданиям.
В настоящее время я использую SCALA-библиотеку 2.11.8
Thankyou

ответ

2

Вы можете думать об использовании оригинал декларации с предполагаемыми видами, как «найти A и B таким образом, что x имеет тип A, y имеет тип B и A является подтип B ".Поскольку A = String и B = Any удовлетворяют этим условиям, компилятор правильно их передает (есть и другие решения, например A = B = Any, но это наиболее конкретный).

Но вы можете изменить объявление, чтобы сообщить компилятору «найти A и B таким образом, что x имеет тип A и y имеет тип B, а затем проверить, что A является подтипом B». Это делается следующим образом:

def fooNew[A,B](x:A,y:B)(implicit evidence: A <:< B): (A,B)=(x,y) 

Это работает потому, что компилятор будет использовать только первый список параметров для вывода A и B. Найдите «ограничения обобщенного типа», чтобы найти дополнительную информацию о <:< и =:=.

+0

Это замечательно. Просто увеличил мои знания о типах вывода и ограничениях типа. – Samar

+0

это именно то, что я хотел ... идеальное решение –

3
def fooNew[A<:B,B](x:A,y:B):(A,B)=(x,y) 

В выше вы объявляющем параметре типа А быть подтипом параметра B. типа При передаче в качестве строки и B, как Int, компилятор поднимается по иерархии классов, чтобы найти подходящий тип для B, так что Int - это B, а также Строка - это подтип B. Единственным типом в иерархии, который удовлетворяет этим двум условиям, является тип Any. Таким образом, String является подтипом Любой и Int имеет тип Любой

+0

, но should'nt, что вызывает ошибку, потому что мой мотив за то, что это encocing типов на оба аргумента. –

+0

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

+1

Для принудительного применения определенного типа вы можете указать specfic-тип в параметр типа. Если вы не предоставляете конкретный тип, то для компилятора он подходит для поиска другого типа, который удовлетворяет определению вашего метода. – Samar