2011-12-15 20 views
5

Nel capitolo 22 di "Programming in Scala" libro, gli :: classe (contro) è definito comeUsando nuova con Scala classe ultimo caso

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

Il metodo :: in classe List è definito come segue:

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

Perché la new necessari per creare un'istanza della finalcaseclass ::? Questo è puramente di disambiguazione?

+4

final significa solo che la classe non può essere estesa, non ha nulla a che fare con la creazione di istanze :-). La classe Case è fondamentalmente una classe che può essere confrontata in un blocco "match case". – aishwarya

risposta

6

Con le classi caso si ottiene automaticamente un oggetto associato il cui apply metodo chiama il costruttore, allo stesso modo, come si può fare questo con una classe 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 

È possibile creare un'istanza classi case con new se volere. In teoria potrebbe essere leggermente più veloce perché non deve passare attraverso il metodo apply dell'oggetto companion, ma ho provato un benchmark rapido e non ho visto alcuna differenza nelle prestazioni, quindi suppongo che sia ottimizzato dal compilatore, o solo un incommensurabile piccolo differenza rispetto alla costruzione attuale.

Quindi non penso che lo new nell'esempio che si dà abbia alcun significato e potrebbe anche essere stato escluso.

3

Sei corretto; il new non è obbligatorio. Avrebbero potuto definito il metodo di istanza List#:: come questo altrettanto bene:

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

(Si noti che abbiamo:

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

definito nell'oggetto scala pacchetto: il primo è il motivo per cui i tuoi new scala.::(x, this) opere, e il secondo è il motivo per cui il mio scala.::(x, this) funziona.)

The form the library uses chiama direttamente il costruttore, come fa il vostro. L'alternativa chiama il metodo apply dell'oggetto companion sintetico generato per la classe di case ::, che chiama comunque il costruttore. Forse chiamare il costruttore è stato ritenuto più chiaro o più efficiente? (. Gli incrementi di efficienza dovrebbe essere vicino a niente, però, dato che se il compilatore non inline la chiamata alla apply, la JVM) suppongo la forma più compatta:

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

potrebbe essere scambiato per un po 'strambo (cioè, impossibile) tipo di invocazione ricorsiva, e in ogni caso offusca la distinzione tra la classe chiamata :: e il metodo chiamato ::, che il Prof. Odersky si impegna a tenere separati per massimizzare la comprensione del lettore.

Spero che questo aiuti.

Problemi correlati