我的项目中有表示ID的对象。
假设它是ChairId、TableId、LampId。我希望他们都继承GenericId。我希望能够呼叫def f(x: GenericId) = x.id
我希望它们只持有单个id: String
,所以我想让它们扩展AnyVal。
此外,我希望每种类型都提供函数generate
,它将生成我的特定ID,即我希望键入类似ChairId.generate()
的内容
我打了这个:
sealed abstract class GenericId(val id: String)
final case class ChairId(override val id: String) extends GenericId(id)
final case class TableId(override val id: String) extends GenericId(id
我想如果GenericId继承AnyVal,那会奏效,但到目前为止运气不佳;/我还尝试将GenericId作为一种特性,并使case类使用GenericId扩展AnyVal,但也不会编译:/
TableId.generate()
的另一件事是,我可以通过函数generate
提供伴随对象,这基本上解决了我的问题,但我想知道是否有可能在不定义伴随对象的情况下解决这个问题?(即通过隐含者)
//编辑
关于提供未编译代码的注释(我想):
sealed abstract class AbstractId(val id: String) extends AnyVal
final case class CatId(override val id: String) extends AbstractId(id)
final case class DogId(override val id: String) extends AbstractId(id)
由于以下几个原因,值类不能以这种方式工作。
首先,从文档来看,值类不能由任何其他类扩展,因此AbstractId
不能扩展AnyVal
。(限制#7)
scala> abstract class AbstractId(val id: String) extends AnyVal
<console>:10: error: `abstract' modifier cannot be used with value classes
abstract class AbstractId(val id: String) extends AnyVal
^
其次,即使您将AbstractId
作为特征,并定义其他id如下:
final case class DogId(val id: String) extends AnyVal with AbstractId
value类的用法不适合您的情况,因为类本身仍然会被分配。参见分配摘要:
当:时,值类实际上被实例化
- 值类被视为另一种类型
- 一个值类被分配给一个数组
- 进行运行时类型测试,例如模式匹配
价值类SIP中的一些引号可能会澄清您的疑虑:
值类。。。
。。。必须只有一个只有一个公共val的主构造函数类型不是值类的参数。
。。。不能由其他类扩展。
按照1。它不能是抽象的;按照2。你的编码不起作用。
还有一个警告:
值类只能扩展通用特征,不能扩展它本身通用特性是扩展Any的特性,只有def作为成员,并且不进行初始化。通用特性允许基本值类的方法的继承,但它们会产生开销分配。
考虑到所有这些,根据您的最后一个片段,这可能会奏效:
sealed trait AbstractId extends Any { def id: String }
final case class CatId(id: String) extends AnyVal with AbstractId
final case class DogId(id: String) extends AnyVal with AbstractId
但请记住,只有当您想使用CatId和DogId作为AbstractId时,才会进行分配。为了更好地理解,我建议阅读SIP。