2016-11-05 5 views
3

Ich habe versucht, eine Funktion mit einem generischen Rückgabetyp zu schreiben, aber es funktioniert nicht, wenn ich den Rückgabetyp umwandelt. Bitte beachten Sie die Funktion getSomething() unten Ich erwartete, dass es ohne das Gießen funktioniert. Was könnte ich hier falsch machen?scala generische Funktion Rückgabetyp

trait Sup 

class Sub extends Sup { 
    def getString = "I am Sub" 
} 

class Sub2 extends Sup { 
    def getInt = 100 
} 

def getSomething[A <: Sup](str: String) : A = { 
    str match { 
    case "sub" => getSub.asInstanceOf[A] 
    case "sub2" => getSub2.asInstanceOf[A] 
    } 
} 

def getSub(): Sub = { 
    new Sub 
} 

def getSub2() : Sub2 = { 
    new Sub2 
} 

val x = getSomething[Sub]("sub").getString 
val y = getSomething[Sub2]("sub2").getInt 

Antwort

1

Wie Alexey erwähnt, wird instanceOf benötigt, um eine Verbindung zwischen dem erwarteten Typ und dem Typ des zurückgegebenen Objekts zu erzwingen. Es ist das Äquivalent zu sagen: "Compiler, vertrau mir, ich gebe dir ein A" und es ist nicht sehr sicher, da es von uns abhängt, einen korrekten Typ anzugeben.

Wenn wir wollen, dass das Typsystem die Dinge für uns herausfindet, müssen wir ihm einige zusätzliche Informationen geben. Eine Möglichkeit, dies in Scala zu tun, besteht darin, eine Fabrik zu definieren, die weiß, wie man Instanzen unserer Typen herstellt, und Beweise, die es dieser Fabrik ermöglichen, unsere spezifischen Typen zurückzugeben.

Dies ist eine Version des obigen Codes, die ein solches Konstrukt einführt und ContextBounds verwendet, um die richtige Factory-Instanz des gewünschten Typs zu erhalten.

trait Sup 

class Sub extends Sup { 
    val str = "I'm a Sub" 
} 

class Sub2 extends Sup { 
    val number = 42 
} 

trait SupProvider[T <: Sup] { 
    def instance:T 
} 

object SupProvider { 
    def getSomeSup[T<:Sup:SupProvider]: T = implicitly[SupProvider[T]].instance 
    implicit object SubProvider extends SupProvider[Sub] { 
    def instance = new Sub 
    } 
    implicit object Sub2Provider extends SupProvider[Sub2] { 
    def instance = new Sub2 
    } 
} 

SupProvider.getSomeSup[Sub].str 
// res: String = I'm a Sub 

SupProvider.getSomeSup[Sub2].number 
// res: Int = 42 
1

Die Fehlermeldungen Sie ohne asInstanceOf bekommen sagen Ihnen genau, was Sie falsch machen. In case "sub" gibt der Körper eine Sub, und der Compiler hat keinen Grund zu denken, A ist ein Supertype von Sub (oder dass Sub implizit in A konvertiert werden kann).

Angenommen, es hat funktioniert. Dann wären die folgenden Anrufe legal:

val z = getSomething[Sub]("sub2").getString 

oder

trait Sub3 extends Sup 
val w = getSomething[Sub3]("sup") 

Was in jedem Fall passieren sollte?

Verwandte Themen