Constructor privado de clase de caso Scala pero método de aplicación pública.
apply case-class (3)
Aquí está la técnica para tener un constructor privado y un método de aplicación público .
trait Meter {
def m: Int
}
object Meter {
def apply(m: Int): Meter = { MeterImpl(m) }
private case class MeterImpl(m: Int) extends Meter { println(m) }
}
object Application extends App {
val m1 = new Meter(10) // Forbidden
val m2 = Meter(10)
}
Información de fondo private-and-protected-constructor-in-scala
Si tengo la siguiente clase de caso con un constructor privado y no puedo acceder al método de aplicación en el objeto complementario.
case class Meter private (m: Int)
val m = Meter(10) // constructor Meter in class Meter cannot be accessed...
¿Hay una manera de usar una clase de caso con un constructor privado pero mantener el método de aplicación generado en el público complementario?
Soy consciente de que no hay diferencia (en mi ejemplo) entre las dos opciones:
val m1 = new Meter(10)
val m2 = Meter(10)
Pero quiero prohibir la primera opción.
editar
Sorprendentemente, los siguientes trabajos (pero no es realmente lo que quiero):
val x = Meter
val m3 = x(10) // m3 : Meter = Meter(10)
Es posible con algunos trucos implícitos:
// first case
case class Meter[T] private (m: T)(implicit ev: T =:= Int)
object Meter {
def apply(m: Int) = new Meter(m + 5)
}
creó otro constructor (y aplica la firma del método) pero la garantía de que el parámetro solo puede ser Int
.
Y después de que tenga clase de caso con características de clase de caso (con coincidencia de patrón, hashcode y equals ) excluya el constructor predeterminado:
scala> val m = Meter(10)
m: Metter[Int] = Meter(15)
scala> val m = new Meter(10)
<console>:9: error: constructor Meter in class Meter cannot be accessed in object $iw
val m = new Meter(10)
O con etiquetado de tipo (implementación ingenua):
trait Private
case class Meter private (m: Integer with Private)
object Meter {
def apply(m: Int) = new Meter((m + 5).asInstanceOf[Integer with Private])
}
Funciona como se espera:
val x = new Meter(10)
<console>:11: error: constructor Meter in class Meter cannot be accessed in object $iw
new Meter(10)
^
val x = Meter(10)
x: Meter = Meter(15)
Algunos posibles problemas con los tipos primitivos y etiquetas de tipo descritos here
Parece que el comportamiento solicitado (constructor privado pero aplicación pública) puede ser la forma en que Scala 2.12 implementa esto.
Llegué a esto desde el ángulo opuesto: me gustaría que un constructor privado de clases de casos también bloquee el método .apply
. Razones aquí: https://github.com/akauppi/case-class-gym
Interesante, cómo difieren los casos de uso.