2016-07-28 2 views
1

Ich habe eine generische Eigenschaft SomeTrait definiert als so:Typ Folgerung mit existenzieller Art

trait SomeTrait[T] { 
    def foo(t: T): String 
} 

und Methoden bar und qux wie so:

def bar[T](t: SomeTrait[T]): T 
def qux: List[SomeTrait[_]] 

Ich habe keine Kontrolle über die oben. Ich versuche, auf der Liste von qux, wie so

qux map { x => x.foo(bar(x))} 

jedoch der Compiler zurück arbeiten beschwert sich, dass die Arten nicht übereinstimmen. Soweit ich weiß, sollte das in Ordnung sein.

Ich habe versucht, eine generische Methode (Signatur [T](SomeTrait[T])String) hinzuzufügen, und das, um die Arbeit zu tun, aber der Compiler beschwert sich noch. Ich kann warf meinen Weg um es so:

qux map { x => 
    val casted = x.asInstanceOf[SomeTrait[T forSome { type T }]] // !!! 
    casted.foo(bar(casted)) 
} 

Aber das ist noch verwirrender, als x bereits den Typ SomeTrait[_] hat und SomeTrait[T forSome { type T }] bedeutet das Gleiche. Der einzige Unterschied, den ich kenne, ist, dass ersterer eine Abkürzung für Letzterer ist, der den Compiler dazu bringt, seine eigenen synthetischen Namen zu erstellen. Ich hoffe, es gibt einen besseren Weg, dies zu tun. Ich habe this question gesehen, aber ich denke nicht, dass es gilt.

+0

Letzteres Beispiel nicht entweder. 'bar' erwartet Typ' T', aber qux gibt grundsätzlich eine 'List [SomeTrait [Any]]' zurück, die nicht mit dem Typ 'T' Argument übereinstimmt. –

+0

@YuvalItzchakov Wenn Sie 'def qux: List [SomeTrait [Any]]' versuchen, wird es gut funktionieren, das ist also nicht das Problem. –

+0

@YuvalItzchakov Letzteres kompiliert einfach gut. – HTNW

Antwort

2

Der richtige Weg, dies zu tun, ist eine Variable vom Typ zu verwenden, um einen Namen zu T geben:

qux map { case x: SomeTrait[t] => x.foo(bar(x)) } 

diese Weise kann der Compiler weiß bar(x): t und so ist es ein akzeptables Argument x.foo.

Oder alternativ können Sie foo und bar in ein Verfahren kombinieren (denken Sie daran, dass Methoden lokal sein können, so dass man es nur definieren kann, wo Sie sie brauchen): kompiliert

def fooOfBar[T](x: SomeTrait[T]) = x.foo(bar(x)) 
qux map { fooOfBar(_) } 
+0

Was ist 't' und wie ist es ein akzeptables Argument für' x.foo'? Kannst du es ausarbeiten? –

+0

@YuvalItzchakov Es ist eine Art Variablenmuster, siehe http://scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#type-patterns. Sie können den existentiellen Parameter nur in einer Musterübereinstimmung benennen, wie der erste Satz sagt. Und weil 'SomeTrait [T] .foo' einen' T'-Parameter benötigt, braucht 'SomeTrait [Int] .foo' natürlich' Int' und 'SomeTrait [t] .foo' braucht' t'. –

+0

Letzteres ist tatsächlich * wirklich * seltsam, da das Weglassen der geschweiften Klammern ('qux map fooOfBar') den Compiler dazu bringt, sich erneut über Typen zu beschweren. Aber es funktioniert gut wie es gegeben ist. Warum passiert das? – HTNW

Verwandte Themen