43

如果我有以下带有私有构造函数的案例类,并且我无法访问伴随对象中的应用方法。

case class Meter private (m: Int)

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

有没有办法使用带有私有构造函数的案例类,但将生成的应用方法保留在伴随的公共中?

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

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

但我想禁止第一个选项。

- 编辑 -

令人惊讶的是,以下作品(但不是我真正想要的):

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

3 回答 3

50

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

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-protected-constructor-in-scala

于 2013-11-17T13:10:22.080 回答
3

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

我从相反的角度得出这个结论——希望私有案例类构造函数也阻止该.apply方法。原因在这里:https ://github.com/akauppi/case-class-gym

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

于 2018-06-22T17:33:08.780 回答
1

有一些隐含的技巧是可能的:

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

或带有类型标记(天真的实现):

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)

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

于 2013-11-17T13:55:55.507 回答