2016-10-06 10 views
0

Ich möchte so etwas wie die folgenden Funktionen ausführen:Wie Variable als Scala-Typ-Parameter verwenden?

val aoeu = List((0, 1), (0, 1, 2)) 
List(Tuple2, Tuple3).foreach { snth => 
    println(aoeu.filter(_.isInstanceOf[snth]).map(_.asInstanceOf[snth])) 
} 

Ist das möglich?

+0

Ja, aber es wird komplex und bricht die Kompilierungszeitsicherheit. Siehe https://medium.com/@sinisalouc/overcoming-type-erasure-in-scala-8f2422070d20#.8ohbqsjqg – spiffman

+0

In Scala ist es einfach, einen Typ zu übergeben und einen Wert zurückzugewinnen, indem man implicits verwendet; aber es ist viel schwieriger (und unsicher), einen Wert zu übergeben und einen Typ zurück zu bekommen. In Ihrem Beispiel kann es meistens funktionieren, wenn Sie 'val snth = Product' durch 'type snth = Product' ersetzen, mit Ausnahme des Laufzeitfehlers, weil Sie ein' Boolean' in ein 'Product' umwandeln. Was ist dein eigentliches Ziel? – Yawar

+0

Wie @Yawar gezeigt hat, nachdem Sie zu 'type snth = Product' gewechselt haben, ist' aoeu.isInstanceOf [snth] 'ein boolescher Wert und kann daher nicht als Instanz von' snth' umgewandelt werden. –

Antwort

0

Wie schon erwähnt, ist es in Scala typensicher und (relativ) einfach, einen Typparameter zu übergeben und einen Wert zurück zu bekommen. Was schwierig und nicht kompilierfähig ist, geht in die andere Richtung. Zu Ihrer Frage, wie sie aussieht, ist die Antwort ... irgendwie. Wir können eine Typklasse definieren, um die Idee der sicheren Konvertierung zu erfassen, einige Instanzen für die Typen einrichten, an denen wir interessiert sind, und dann unsere Operationen ausführen. Also hier ist, was ich habe:

import scala.util.Try 

/** 
A typeclass to represent safe casting behaviour. 
*/ 
trait HasInstance[A] { def apply(any: Any): Option[A] } 

object HasInstance { 
    /** 
    A helper to quickly create a typeclass instance. 
    */ 
    private class Impl[A](_apply: Any => Option[A]) 
    extends HasInstance[A] { 
    override def apply(any: Any): Option[A] = _apply(any) 
    } 

    /* Instances for standard types. */ 

    implicit val int: HasInstance[Int] = 
    new Impl(any => Try(any.asInstanceOf[Int]).toOption) 

    implicit def tuple2[A, B]: HasInstance[Tuple2[A, B]] = 
    new Impl(any => Try(any.asInstanceOf[Tuple2[A, B]]).toOption) 

    implicit def tuple3[A, B, C]: HasInstance[Tuple3[A, B, C]] = 
    new Impl(any => Try(any.asInstanceOf[Tuple3[A, B, C]]).toOption) 
} 

object Test { 
    def test(): Unit = { 
    val xs = List((0, 1), (0, 1, 2)) 

    // Flatmap will automatically filter out `None` values. 

    println(xs flatMap implicitly[HasInstance[Tuple2[Int, Int]]].apply) 
    // ==> List((0, 1)) 

    println(
     xs flatMap implicitly[HasInstance[Tuple3[Int, Int, Int]]].apply) 
    // ==> List((0, 1, 2)) 
    } 
} 

Bitte beachte, dass wir noch keine Instanzen in einer Liste erfassen können, weil ihre Typen würden Scala zwingen upCast zu AnyRef sie zusammen zu speichern. Wenn Sie heterogene Listen haben und abbilden möchten, befinden Sie sich in Formlosem Gebiet. In der Tat, Sie könnten es trotzdem sein, weil Sie wahrscheinlich eine generische Ableitung durchführen möchten, um Instanzen für HasInstance einfach ableiten zu können.

Verwandte Themen