Ausgabe
Ich verwende Scala 2.11. Ich habe eine Frage zu den generischen Scala-Typen und dem Musterabgleich.
In der Klasse MyImpl.example()
ist Compiler unglücklich zu sagentype mismatch, Required: _$1, Found: X[_ <: A]
trait A
class B extends A
class C extends A
trait Foo[T <: A] {
def foo(arg: T): Unit
}
class Bar extends Foo[B] {
override def foo(arg: B): Unit = print("Bar")
}
class Car extends Foo[C] {
override def foo(arg: C): Unit = print("Car")
}
class MyImpl {
def getA(): A = {
new B()
}
def example(): Unit = {
getFoo("1").foo(getA())
}
def getFoo(something: String): Foo[_ <: A] = {
//return either
something match {
case "1" => new Bar()
case "2" => new Car()
}
}
}
object Test {
def main(args: Array[String]) = {
new MyImpl().example()
}
}
Hinweis: getFoo(“1”) ist in meinem realen Fall dynamischer, hier ist nur ein Beispiel.
Ich verstehe das irgendwie, der Compiler kann nicht vorhersagen, auf welchem Paar der 2-Implementierung die Methode aufgerufen wird.
Ich kann dies umgehen, wenn ich die Implementierung von MyImpl.example()
zu ändere
def example(): Unit = {
(getFoo("1"), getA()) match {
case (i: Bar, j: B) => i.foo(j)
case (i: Car, j: C) => i.foo(j)
}
}
Ich bin nicht wirklich glücklich damit, da ich mich nur wiederholei.foo(j)
Gibt es einen Scala-Funktionsstil, der viel saubereren Code schreibt?
Lösung
Im Grunde wollen Sie so etwas wie
(getFoo("1"), getA()) match {
case (i: Foo[t], j: t) => i.foo(j) // doesn't compile, not found: type t
}
oder
(getFoo("1"), getA()) match {
case (i: Foo[t], j: Id[t]) => i.foo(j) // doesn't compile, t is already defined as type t
}
type Id[T] = T
Sie können die Codeduplizierung in entfernen
def example(): Unit = { // (*)
(getFoo("1"), getA()) match {
case (i: Bar, j: B) => i.foo(j)
case (i: Car, j: C) => i.foo(j)
}
}
(oder Kompilierung von beheben getFoo("1").foo(getA())
)
mit verschachteltem Musterabgleich
getFoo("1") match {
case i => getA() match {
case j: i._T => i.foo(j)
}
}
wenn Sie Typmitglied hinzufügen_T
trait Foo[T <: A] {
type _T = T
def foo(arg: T): Unit
}
Für getFoo("1")
und getA
Herstellung new B
dieser Drucke Bar
, umgekehrt für getFoo("2")
und new C
diese Drucke Car
, für andere Kombinationen wirft dies ClassCastException
ähnlich wie (*).
Bitte beachten Sie, dass dies nicht einfach als Variablendeklaration und Einzelmusterabgleich umgeschrieben werden kann
val i = getFoo("1")
getA() match {
case j: i._T => i.foo(j)
}
//type mismatch;
// found : j.type (with underlying type i._T)
// required: _$1
denn für den verschachtelten Musterabgleich werden die Typen korrekt abgeleitet ( i: Foo[t]
, j: t
), aber für val i
den Typ ist existenziell ( auch bekannt als nach der i: Foo[_]
Skolemisierung , ).i: Foo[_$1]
j: _$1
Beantwortet von – Dmytro Mitin
Antwort geprüft von – Timothy Miller (FixError Admin)