2015-03-30 5 views
3

Можно ли пролить свет на реальные различия между этими двумя примерами.Параметр неограниченного подстановочного типа против абстрактного типа

object ExampleA { 
    trait Bar { def n: Int } 
    trait Foo[B <: Bar] { def bar: B } 

    def getBarIntFromFoo(foo: Foo[_]) = 
     getBarInt(foo.bar) 

    def getBarInt(bar: Bar) = 
     bar.n 
} 

object ExampleB { 
    trait Bar { def n: Int } 
    trait Foo { 
     type B <: Bar 
     def bar: B 
    } 

    def getBarIntFromFoo(foo: Foo) = 
     getBarInt(foo.bar) 

    def getBarInt(bar: Bar) = 
     bar.n 
} 

Я предположил, что единственным отличием было то, как вы обратитесь к ним, но в действительности только ExampleB компилирует и ExampleA результаты в:

[error] type mismatch; 
[error] found : _$1 
[error] required: ExampleA.Bar 
[error]  getBarInt(_) 
[error]    ^

Оба Foo с имеют те же ограничения типа (B <: Bar), поэтому я немного потерян. Полагаю, я просто недопонимаю что-то довольно основное.

ответ

3

_ в Foo[_] является экзистенциальным типом. Без каких-либо ограничений по типу он будет считаться Any, хотя Foo[B] имеет верхнюю границу Bar. Это означает, что foo.bar считается Any, а не Bar. Таким образом, getBarInt(foo.bar) терпит неудачу, потому что компилятор считает, что вы передаете Any вместо Bar.

Если вы хотите, чтобы параметр был Foo[_], он должен быть ограничен здесь.

object ExampleA { 
    trait Bar { def n: Int } 
    trait Foo[B <: Bar] { def bar: B } 

    def getBarIntFromFoo(foo: Foo[_ <: Bar]) = 
     getBarInt(foo.bar) 

    def getBarInt(bar: Bar) = 
     bar.n 
} 

От SLS:

Scala поддерживает синтаксис-заполнитель для экзистенциальных типов. Тип подстановочных знаков имеет вид _ >: L <: U. Оба связанных предложения могут быть опущены. Если отсутствует нижняя граница раздела >: L, предполагается, что принимается >: scala.Nothing. Если отсутствует верхний раздел оговорки <: U, <: scala.Any принимается. Тип подстановочных знаков является сокращением для экзистенциально квантифицированной переменной типа, где экзистенциальная квантификация неявно.

Второй пример с псевдонимом типа просто не страдает от этого.

+0

Итак, хотя верхняя граница определена для типа, она все еще компилируется как «Любой», а не «Любой в пределах границ, определенных для типа»? – adlawson

+0

Это правильно. –

+0

Bums. Спасибо за вашу помощь! – adlawson

3

m-z здесь правильный. Но один вопрос, который вы можете задать, заключается в следующем: почему Scala требует от вас повторить привязку <: Bar, если это уже требуется по определению Foo?

Причина заключается в согласованности с

def blah[A](f: Foo[A]) 

Здесь [A] собирается подаваться вызывающим, так Foo не может быть разрешено применять любые дополнительные ограничения на нем (в противном случае точного определения бла бы трудно определить). Это означает, что в целом Foo[x] не может применять ограничения к X, хотя в некоторых случаях это было бы безопасно.

Однако есть планы на будущее, чтобы повторно реализовать экзистенциальные типы в качестве переменных типа, поэтому, возможно, такое поведение изменится когда-нибудь.

+0

Полагаю, это был вопрос, который меня больше всего раздражал. Согласованность имеет смысл.Я оставлю m-z в качестве принятого ответа, но спасибо, что прояснил ситуацию! – adlawson

Смежные вопросы