2010-12-13 5 views
5

Ich versuche, eine Scala Merkmal zu implementieren, die die Details einer Schnittstelle mit einem Java-Bibliothek, die unsWie kann ich die Laufzeit der Klasse eines parametrisierte Typ in einer Scala Zug bekommen

erstellen erfordert Griffe Was ich will sie ist so etwas wie:

trait SomeTrait[A] extends JavaAPI { 
    def foo = { 
    callApi(classOf[A]) 
    } 

    override def bar = { 
    foo 
    } 
} 

Beachten sie, dass Bar tatsächlich eine Methode aus einer Basisklasse überschreibt, so kann ich es Unterschrift nicht ändern.

Ich habe verschiedene Varianten mit Manifesten usw. ausprobiert, aber das kann nicht ganz funktionieren. Gibt es eine Möglichkeit, die Laufzeitklasse eines parametrisierten Typs zu erhalten?

Antwort

10

Dieser Geschmack, den Trick tun soll:

trait SomeTrait[A] { 
    def foo(implicit ev: Manifest[A]) = { 
    callApi(ev.erasure) 
    } 
} 

Update An einem gewissen Punkt muss das Manifest über einen Methodenparameter injiziert werden. Ein Konstrukteur wäre eine gute Wahl, wenn Merkmale sie haben könnten.

Eigentlich können sie! Der Zug hat den Konstruktor von was auch immer es ist gemischt-in, wenn Sie also ein abstraktes Manifest angeben, dass Ableitung Klassen muss definieren ...

trait SomeTrait { 
    def ev: Manifest[_] //abstract 
    def foo = println(ev.erasure) 
} 

//this `ev` provides the implementation, note that it MUST be a val, or var 
class Concrete[T](implicit val ev: Manifest[T]) extends SomeTrait 

Und alles ist wieder gut.

+0

Dies ist in der Nähe, aber ich muss foo() aus dem Merkmal heraus aufrufen. Wenn ich das mit diesem Ansatz versuche, bekomme ich einen Compilerfehler: "konnte keinen impliziten Wert für Parameter ev finden: Manifest [A]. Ich habe mein Beispiel aktualisiert, um die (genauere) Spezifikation wiederzugeben. –

+0

' ev.erasure' ist veraltet, Sie sollten jetzt ev.runtimeClass verwenden. – wizulus

4

Aufgrund von Typ löschen, der Compiler hat keine Möglichkeit herauszufinden, was der Typ innerhalb des Merkmals sein sollte. Also was Sie wollen, kann nicht getan werden. Sie könnten es jedoch zu einer Klasse machen. Auf diese Weise kann der Compiler beim Erstellen einer Instanz einen Beweisparameter übergeben.

class SomeTrait[A](implicit ev: Manifest[A]) extends JavaApi { 
    def foo = { 
    callApi(ev.erasure) 
    } 


    override def bar = { 
    foo 
    } 
} 
5

Sie müssen das Manifest irgendwie dorthin bringen, und Eigenschaften haben keine Konstruktorparameter. Nur Sie können sagen, welchen Kompromiss Sie eingehen möchten. Hier ist ein anderes.

trait SomeTrait[A] { 
    implicit def manifesto: Manifest[A] 

    def foo = println(manifest[A].erasure) 
} 
object SomeTrait { 
    def apply[A: Manifest] : SomeTrait[A] = new SomeTrait[A] { def manifesto = manifest[A] } 
} 
0

Es könnte ein wenig unbequem sein, so im Code zu tun, aber Sie tun können, um diese

trait SomeTrait[A] extends JavaAPI { 
    def objType: Class[A] 
    def foo = { 
    callApi(objType) 
    } 

    override def bar = { 
    foo 
    } 
} 

object SomeImplementation with SomeTrait[SomeObject] { 
    val objType: Class[SomeObject] = classOf[SomeObject] 
} 

Ich weiß, es ist ein wenig wortreich ist, aber das ist die Art, wie ich dieses Problem gelöst. Ich hoffe, in Zukunft eine bessere Lösung zu finden, aber das ist es, was ich jetzt benutze. Lass es mich wissen, wenn dir das hilft.

Verwandte Themen