1

我的项目中有代表 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 成为一个特征,并使案例类使用 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)
4

2 回答 2

3

由于几个原因,值类不能以这种方式工作。

首先,从文档来看,值类不能被任何其他类扩展,所以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

..值类的使用不适合您的情况,因为类本身仍会被分配。请参阅分配摘要

值类实际上在以下情况下被实例化:

  1. 值类被视为另一种类型。
  2. 一个值类被分配给一个数组。
  3. 进行运行时类型测试,例如模式匹配。
于 2016-07-31T17:18:59.397 回答
1

价值类 SIP中的一些引用可能会澄清您的疑问:

价值等级...

  1. ...必须只有一个主构造函数,其中只有一个公共的 val 参数,其类型不是值类。

  2. ...不能被另一个类扩展。

1.不能是抽象的;每 2. 您的编码不起作用。

还有一个警告:

值类只能扩展通用特征,不能扩展自身。通用特征是扩展 Any 的特征,只有 defs 作为成员,并且不进行初始化。通用特征允许对值类的方法进行基本继承,但它们会产生分配开销。

考虑到所有这些,根据您的最后一个片段,这可能有效:

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。

于 2016-07-31T17:20:16.103 回答