2010-12-13 70 views
5

Je suis en train de mettre en œuvre un trait Scala qui gère les détails de l'interface avec une bibliothèque Java qui nous oblige à créerComment puis-je obtenir la classe d'exécution d'un type paramétrés dans un trait Scala

Ce que je veux faire est quelque chose comme:

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

    override def bar = { 
    foo 
    } 
} 

Notez que la barre est prépondérant en fait une méthode d'une classe de base, donc je ne peux pas changer sa signature.

J'ai essayé plusieurs variantes avec Manifests, etc., mais je n'arrive pas à le faire fonctionner. Est-il possible d'obtenir la classe d'exécution d'un type paramétré?

Répondre

10

Cette saveur devrait faire l'affaire:

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

mise à jour À un certain moment, le manifeste doit être injecté via un paramètre de méthode. Un constructeur serait un bon choix, si les traits pouvaient les avoir.

En fait, ils peuvent! Le trait a le constructeur de ce qu'il est mixte pour, donc si vous spécifiez un manifeste abstrait que les classes dérivées doivent définir ...

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 

Et tout est bon à nouveau.

+0

Ceci est proche, mais j'ai besoin d'appeler foo() à l'intérieur du trait. Lorsque j'essaie avec cette approche, j'obtiens une erreur de compilation: "Impossible de trouver la valeur implicite pour le paramètre ev: Manifest [A] .J'ai mis à jour mon exemple pour refléter la spécification (plus précise) –

+0

' ev.erasure' est obsolète, vous devriez maintenant utiliser 'ev.runtimeClass'. – wizulus

4

En raison de l'effacement de type, le compilateur n'a aucun moyen de déterminer quel type devrait être dans le trait. Donc ce que vous voulez ne peut pas être fait. Cependant, vous pourriez en faire une classe. De cette façon, le compilateur peut passer un paramètre de preuve lors de la création d'une instance.

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


    override def bar = { 
    foo 
    } 
} 
5

Vous devez obtenir le manifeste à l'intérieur d'une manière ou d'une autre, et les traits n'ont pas de paramètres constructeurs. Vous seul pouvez dire quel compromis vous voulez faire. En voici un autre.

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

Il est peut-être un peu gênant de le faire dans votre code, mais vous pouvez le faire

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] 
} 

Je sais qu'il est un peu verbeux, mais c'est la façon dont je l'ai résolu ce problème. J'espère trouver une meilleure solution à l'avenir, mais c'est ce que j'utilise maintenant. Faites-moi savoir si cela vous aide.