2010-12-13 27 views
5

estoy tratando de poner en práctica un rasgo Scala que se encarga de los detalles de la interfaz con una biblioteca de Java que nos obliga a crear¿Cómo consigo la clase en tiempo de ejecución de un tipo parametrizado en un rasgo Scala

Lo que quiero hacer es algo como:

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

    override def bar = { 
    foo 
    } 
} 

Tenga en cuenta que la barra es en realidad sustituir un método de una clase base, por lo que no puede cambiar su firma.

He intentado varias variaciones con Manifests, etc., pero no puedo hacer que esto funcione. ¿Hay alguna manera de obtener la clase de tiempo de ejecución de un tipo parametrizado?

Respuesta

10

Este sabor debe hacer el truco:

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

actualización En algún momento, el manifiesto se debe inyectar a través de un parámetro del método. Un constructor sería una buena opción, si los rasgos pudieran tenerlos.

¡En realidad, sí pueden! El rasgo tiene el constructor de lo que es mixto en que, por lo que si se especifica un manifiesto abstracto que las clases derivadas deben definir ...

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 

Y todo está bien otra vez.

+0

Esto está cerca, pero necesito llamar a foo() desde dentro del rasgo. Cuando intento eso con este enfoque, aparece un error de compilación: "no se pudo encontrar el valor implícito para el parámetro ev: Manifiesto [A]. He actualizado mi ejemplo para reflejar la especificación (más precisa) –

+0

' ev.erasure' está en desuso. Ahora debería usar 'ev.runtimeClass'. – wizulus

4

Debido a la borradura de tipo, el compilador no tiene forma de averiguar cuál debe ser el tipo dentro del trait. Por lo tanto, lo que quieres no se puede hacer. Sin embargo, podrías convertirlo en una clase. De esta forma, el compilador puede pasar un parámetro de evidencia cuando se crea una instancia.

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


    override def bar = { 
    foo 
    } 
} 
5

Usted tiene que conseguir el manifiesto de allí de alguna manera, y los rasgos no tienen parámetros del constructor. Solo tú puedes decir qué compensación deseas hacer. Aqui hay otro más.

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

Podría ser un poco incómodo para hacerlo en su código, pero se puede hacer esto

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

Sé que es un poco prolijo, pero esa es la forma en que resolvió este problema. Espero encontrar una mejor solución en el futuro, pero esto es lo que estoy usando ahora. Avísame si eso te ayuda.

Cuestiones relacionadas