Scala case class private constructor but public apply method

后端 未结 3 1208
萌比男神i
萌比男神i 2020-12-08 06:50

If I have the following case class with a private constructor and I can not access the apply-method in the companion object.

case class Meter private (m: Int         


        
相关标签:
3条回答
  • Here's the technique to have a private constructor and a public apply method.

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

    Background information private-and-protected-constructor-in-scala

    0 讨论(0)
  • 2020-12-08 07:21

    It seems the requested behavior (private constructor but public .apply) may be the way Scala 2.12 implements these.

    I came to this from the opposing angle - would like a private case class constructor also block the .apply method. Reasons here: https://github.com/akauppi/case-class-gym

    Interesting, how use cases differ.

    0 讨论(0)
  • 2020-12-08 07:28

    It is possible with some implicit tricks:

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

    created some another constructor (and apply method signature) but guaranty that parameter can be only Int.

    And after you have case class with case class features (with pattern matching, hashcode & equals) exclude default constructor:

    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)
    

    OR with type tagging (naive implementation):

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

    It works as expected:

    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)
    

    Some possible issues with primitive types and type tags described here

    0 讨论(0)
提交回复
热议问题