Classe de cas Scala constructeur privé mais méthode d'application publique

si j'ai la classe de cas suivante avec un constructeur privé et que je ne peux pas accéder à la méthode apply dans l'objet compagnon.

case class Meter private (m: Int)

val m = Meter(10) // constructor Meter in class Meter cannot be accessed...

y a-t-il un moyen d'utiliser une classe de cas avec un constructeur privé mais de garder la méthode apply-generated dans le public compagnon?

je suis conscient qu'il n'y a pas de différence (dans mon exemple) entre les deux options:

val m1 = new Meter(10)
val m2 = Meter(10)

mais je veux interdire la première option.

-- edit --

étonnamment les œuvres suivantes (mais n'est pas vraiment ce que je veux):

val x = Meter
val m3 = x(10) // m3  : Meter = Meter(10)
30
demandé sur Erik 2013-11-17 16:47:50

3 réponses

Voici la technique pour avoir un privé constructeur et un méthode d'application publique .

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

informations générales privé et protégé-constructeur-en-scala

36
répondu Farmor 2017-05-23 11:54:13

il est possible avec quelques trucs implicites:

// first case 
case class Meter[T] private (m: T)(implicit ev: T =:= Int)
object Meter { 
  def apply(m: Int) = new Meter(m + 5) 
}

a créé un autre constructeur (et appliquer la méthode signature) mais garantit que le paramètre peut être seulement Int .

et après que vous avez classe de cas avec les caractéristiques de classe de cas (avec correspondance de modèle, hashcode & égale ) exclure constructeur par défaut:

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)

OU avec le type de marquage (implémentation naïve):

trait Private
case class Meter private (m: Integer with Private)
object Meter {
  def apply(m: Int) = new Meter((m + 5).asInstanceOf[Integer with Private])
}

Il fonctionne comme prévu:

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)

quelques problèmes possibles avec les types primitifs et les étiquettes de type décrites ici

0
répondu Yuriy 2017-07-17 09:33:42

il semble que le comportement demandé (constructeur privé mais public .apply ) puisse être la façon dont Scala 2.12 les implémente.

je suis venu à cela de l'angle opposé - comme un constructeur de classe de cas privé aussi bloquer la méthode .apply . Raisons ici: https://github.com/akauppi/case-class-gym

intéressant, comment les cas d'utilisation diffèrent.

0
répondu akauppi 2018-06-22 17:33:08