2011-12-15 8 views
5

En el capítulo 22 de "Programación en Scala" libro, los :: clase (contras) se define comoUtilizando nuevo con Scala clase último caso

final case class ::[T](hd: T, tl: List[T]) extends List[T] { 
    //... 
} 

El método :: en clase List se define como sigue:

def ::[U >: T](x: U): List[U] = new scala.::(x, this) 

¿Por qué el new requiere para crear una instancia de la finalcaseclass ::? ¿Esto es puramente por desambiguación?

+4

final solo significa que la clase no se puede extender, no tiene nada que ver con la creación de instancias :-). La clase de caso es básicamente una clase que se puede comparar en un bloque de "coincidencia". – aishwarya

Respuesta

6

Con las clases de casos se obtiene automáticamente un objeto acompañante cuya apply método llama al constructor, de la misma manera como se puede hacer esto con una clase ordinaria:

class Foo(val value: Int) 
object Foo { def apply(value: Int) = new Foo(value) } 

val x = new Foo(42) // 
val y = Foo(42)  // both work the same 

Puede crear instancias de clases de casos con new si querer. En teoría podría ser un poco más rápido porque no tiene que pasar por el método apply del objeto complementario, pero probé un punto de referencia rápido y no vi absolutamente ninguna diferencia en el rendimiento, así que creo que está optimizado por el compilador, o simplemente es infinitamente pequeño diferencia en comparación con la construcción real.

Así que no creo que el new en el ejemplo que proporcione tenga algún significado y podría haberse omitido.

3

Tiene razón; el new no es obligatorio. Podrían haber definido el método de instancia List#:: como esto tan bien:

def ::[U >: T](x: U): List[U] = scala.::(x, this) 

(Tenga en cuenta que tenemos:

type :: = collection.immutable.:: 
val :: = collection.immutable.:: 

definida en el objeto scala paquete, la primera es por qué sus new scala.::(x, this) obras, y el segundo es por qué mi scala.::(x, this) funciona.)

The form the library uses llama al constructor directamente, como lo hace el tuyo. La alternativa llama al método apply del objeto complementario sintético generado para la clase de caso ::, que simplemente llama al constructor de todos modos. ¿Tal vez llamar al constructor se consideró más claro o más eficiente? (. Las ganancias de eficiencia deben estar cerca de nada, sin embargo, ya que si el compilador no coloca en línea de la llamada a apply, la JVM) supongo que la forma más compacto:

def ::[U >: T](x: U) = ::(x, this) 

podrían confundirse con algún loco (es decir, imposible) tipo de invocación recursiva, y en cualquier caso desdibuja la distinción entre la clase llamada :: y el método List llamado ::, que el Prof. Odersky se esfuerza por mantener separado para maximizar la comprensión del lector.

Espero que esto ayude.

Cuestiones relacionadas