禁止生成申请案例类

Som*_*ame 7 scala type-safety case-class shapeless

我正在编写一个类型安全的代码,并希望用我自己的实现替换apply()case classes生成的代码。这里是:

import shapeless._

sealed trait Data
case object Remote extends Data
case object Local extends Data

case class SomeClass(){
  type T <: Data
}

object SomeClass {
  type Aux[TT] = SomeClass { type T = TT }
  def apply[TT <: Data](implicit ev: TT =:!= Data): SomeClass.Aux[TT] = new SomeClass() {type T = TT}
}

val t: SomeClass = SomeClass() // <------------------ still compiles, bad
val tt: SomeClass.Aux[Remote.type] = SomeClass.apply[Remote.type] //compiles, good
val ttt: SomeClass.Aux[Data] = SomeClass.apply[Data] //does not compile, good
Run Code Online (Sandbox Code Playgroud)

我想禁止val t: SomeClass = SomeClass()编译。是否有可能以某种方式尽除不SomeClasscase class

Mat*_*zok 8

如果您想提供一些智能构造函数,并且默认构造函数会破坏您的不变量,那么通常会使用一种解决方案。为了确保只有您可以创建实例,您应该:

  • 防止使用 apply
  • 防止使用 new
  • 防止使用 .copy
  • 防止在子类可以调用构造函数的地方扩展类

这是通过这个有趣的模式实现的:

sealed abstract case class MyCaseClass private (value: String)
object MyCaseClass {
  def apply(value: String) = {
    // checking invariants and stuff
    new MyCaseClass(value) {}
  }
}
Run Code Online (Sandbox Code Playgroud)

这里:

  • abstract防止产生.copyapply
  • sealed阻止扩展此类(final不允许abstract
  • private 构造函数阻止使用 new

虽然它看起来并不漂亮,但它几乎是防弹的。

正如@LuisMiguelMejíaSuárez 指出的那样,这在您的具体情况下不是必需的,但通常可以用于处理case class智能构造函数的边缘情况。


Lui*_*rez 6

因此,您可以将构造函数T设为私有并确保它与Nothing.

我相信确保构造函数是私有的(以及@MateuszKubuszok 展示的许多其他东西)的最佳方法是使用(密封的) 特征而不是:(
如果您因任何原因无法使用特征,请参阅Mateusz的回答)

import shapeless._

sealed trait Data
final case object Remote extends Data
final case object Local extends Data

sealed trait SomeClass {
  type T <: Data
}

object SomeClass {
  type Aux[TT] = SomeClass { type T = TT }
  def apply[TT <: Data](implicit ev1: TT =:!= Data, ev2: TT =:!= Nothing): Aux[TT] =
    new SomeClass { override final type T = TT }
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理是这样的:

SomeClass() // Does not compile.
SomeClass.apply[Remote.type] // Compiles.
SomeClass.apply[Data] // Does not compile.
Run Code Online (Sandbox Code Playgroud)

你可以看到它在这里运行。