禁止生成申请案例类

问题描述

我正在编写一种类型安全的代码,并想用自己的实现替换为apply() es生成的case class。在这里:

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

我想禁止val t: SomeClass = SomeClass()进行编译。除了不SomeClass成为case class以外,是否可以采取其他方式?

解决方法

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

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

这是通过这个有趣的专利实现的:

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

这里:

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

虽然看起来不漂亮,但几乎可以证明其安全性。

@LuisMiguelMejíaSuárez指出,在您的确切情况下这不是必需的,但通常可以使用智能构造函数来处理case class的边缘情况。

,

因此,您可以将构造函数设为私有,并确保TNothing也有所不同。

我相信确保构造函数为私有(以及@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 }
}

这是这样的:

SomeClass() // Does not compile.
SomeClass.apply[Remote.type] // Compiles.
SomeClass.apply[Data] // Does not compile.

您可以看到它正在运行here

,

如果您想禁止使用案例类的某些自动生成的方法,则可以手动定义方法(带有适当的签名)(然后将不会生成),并将其设置为private(或{{ 1}})。

尝试

private[this]

原则上,方法(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} private def apply(): SomeClass = ??? // added } val t: SomeClass = SomeClass() // doesn't compile val tt: SomeClass.Aux[Remote.type] = SomeClass.apply[Remote.type] //compiles val ttt: SomeClass.Aux[Data] = SomeClass.apply[Data] //doesn't compile applyunapplycopyhashCode)不是由编译器本身生成的,而是由{{ 3}}。然后,您可以选择它们的任何子集,并根据需要修改它们的生成。

macro annotations

Generate apply methods creating a class

此外,可以使用Shapeless 案例类点菜生成方法。然后,您也可以根据需要打开/关闭这些方法。

how to efficiently/cleanly override a copy method

https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/alacarte.scala

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...