Scala case类私有构造函数但是public apply方法

时间:2013-11-17 12:47:51

标签: scala apply case-class private-constructor

如果我有以下具有私有构造函数的case类,并且我无法访问companion对象中的apply-method。

case class Meter private (m: Int)

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

有没有办法将case类与私有构造函数一起使用,但是在公开的伴随文件中保留生成的apply-method?

我知道两个选项之间没有区别(在我的例子中):

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

但我想禁止第一个选项。

- 编辑 -

令人惊讶的是以下作品(但实际上并不是我想要的):

val x = Meter
val m3 = x(10) // m3  : Meter = Meter(10)

3 个答案:

答案 0 :(得分:41)

这是使用私有构造函数和公开应用方法的技术。

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

背景资料private-and-protected-constructor-in-scala

答案 1 :(得分:0)

可能有一些隐含的技巧:

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

创建了另一个构造函数(并应用方法签名),但保证该参数只能是Int

在您拥有案例类功能的案例类(使用模式匹配,哈希码和等于)之后,排除默认构造函数:

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与类型标记(天真实现):

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

按预期工作:

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)

原始类型和类型标记的一些可能问题描述为here

答案 2 :(得分:0)

似乎请求的行为(私有构造函数但公共.apply)可能是Scala 2.12实现这些行为的方式。

我是从相反的角度来看这个问题的-就像一个私人案例类构造函数也阻塞了.apply方法。原因如下:https://github.com/akauppi/case-class-gym

有趣的是,用例有何不同。