2016-06-29 22 views
5

Oggi ho riscontrato uno strano problema con i costruttori della classe case. Volevo rendere privato un costruttore e sembra che non sia un problema. Quindi l'ho provato in uno dei miei progetti e funziona. Ma in un altro progetto posso invocare il costruttore privato e lo compila. Ho pensato che fosse qualcosa con la mia ide, quindi ho creato una lezione autonoma e la ho compilata con scalac. E compila. Ecco il codice:Il costruttore privato Scala class di classe non è privato

package com.test 

object Main { 

    def main(args: Array[String]) { 
    val bar = Bar("12345") 
// bar.doStuff() 
    println(bar) 
    } 
} 

case class Bar private(foo: String){ 
    private def doStuff():Unit = println("stuff") 
} 

La cosa divertente è che se io uncomment bar.doStuff() non sarà compilato. Quindi in questo caso presumo lavori privati, ma in qualche modo non funziona per il costruttore. Che cosa sto facendo di sbagliato? scalac è 2.11.8

risposta

10

La notazione val bar = Bar("12345") è abbreviata per val bar = Bar.apply("12345"), in altre parole, viene chiamato il metodo del (generato automaticamente) companion object della classe case apply.

L'oggetto associato ha accesso al costruttore privato, ecco perché funziona.

(Perché si desidera rendere il costruttore di una classe di caso private? Non sembra una buona idea).

+4

Esattamente. 'val bar = new Bar (" 12345 ")' non funziona – nmat

+0

Grazie per la risposta. Sapevo di applicare il metodo, ma in qualche modo non ci pensavo qui. Per quanto riguarda la tua domanda, voglio avere un campo inizializzato nel metodo apply e solo lì. –

+3

@ArtemMalinko probabilmente sarà più semplice renderlo una normale classe (con opzionalmente un oggetto complementare) in modo da avere il pieno controllo sul costruttore e sul metodo 'apply'. Nota che le classi di casi sono in realtà solo zucchero sintattico, puoi anche fare tutto il necessario con una classe regolare (ma dovrai scrivere alcune cose tu stesso). – Jesper

2

Se si desidera che Bar("abc") non si compili, ecco una soluzione semplice.

Testato rapidamente in 2.12.3. Non funziona in 2.11.8

case class Bar private (value: String) 
object Bar { 
    private def apply(v: String) = new Bar(v) // makes the method private 
    def create(value: String): Bar = ... // your own implementation 
} 

val bar = Bar("abc") // compile error 
val bar = new Bar("abc") // compile error 
val bar = Bar.create("abc") // ok