문제

I have some troubles having Scala to infer the right type from a type projection.

Consider the following:

trait Foo {
  type X
}

trait Bar extends Foo {
  type X = String
}

def baz[F <: Foo](x: F#X): Unit = ???

Then the following compiles fine:

val x: Foo#X = ???    
baz(x)

But the following won't compile:

val x: Bar#X = ???    
baz(x)

Scala sees the "underlying type String" for x, but has lost the information that x is a Bar#X. It works fine if I annotate the type:

baz[Bar](x)

Is there a way to make Scala infer the right type parameter for baz?
If not, what is the general answer that makes it impossible?

도움이 되었습니까?

해결책

The program compiles by adding this implicit conversion in the context:

implicit def f(x: Bar#X): Foo#X = x

As this implicit conversion is correct for any F <: Foo, I wonder why the compiler does not do that by itself.

다른 팁

You can also:

trait Foo {
    type X
}
trait Bar extends Foo {
    type X = String
}
class BarImpl extends Bar{
  def getX:X="hi"
}
def baz[F <: Foo, T <: F#X](clz:F, x: T): Unit = { println("baz worked!")}
val bi = new BarImpl
val x: Bar#X = bi.getX
baz(bi,x)

but:

def baz2[F <: Foo, T <: F#X](x: T): Unit = { println("baz2 failed!")}
baz2(x)

fails with:

test.scala:22: error: inferred type arguments [Nothing,java.lang.String] do not conform to method baz2's type parameter bounds [F <: this.Foo,T <: F#X]
baz2(x)
^
one error found

I think basically, F <: Foo tells the compiler that F has to be a subtype of Foo, but when it gets an X it doesn't know what class your particular X comes from. Your X is just a string, and doesn't maintain information pointing back to Bar.

Note that:

def baz3[F<: Foo](x : F#X) = {println("baz3 worked!")}
baz3[Bar]("hi")

Also works. The fact that you defined a val x:Bar#X=??? just means that ??? is restricted to whatever Bar#X might happen to be at compile time... the compiler knows Bar#X is String, so the type of x is just a String no different from any other String.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top