我有一些case类,它的伴随对象中定义了一个方法 tupled
. 从下面的代码对象中可以看出,它只是代码重复 .
case class Book(id: Int, isbn: String, name: String)
object Book {
def tupled = (Book.apply _).tupled // Duplication
}
case class Author(id: Int, name: String)
object Author {
def tupled = (Author.apply _).tupled // Duplication
}
从另一个问题(can a scala self type enforce a case class type)来看,似乎我们不能强制将特征的自我类型作为案例类 .
有没有办法定义可以如下应用的特征(比如 Tupled
)?
// What would be value of ???
trait Tupled {
self: ??? =>
def tupled = (self.apply _).tupled
}
// Such that I can replace tupled definition with Trait
object Book extends Tupled {
}
2 回答
因为Scala中的
FunctionN
类型之间没有任何关系,所以's not possible to do this without arity-level boilerplate somewhere—there'只是无法在不枚举所有可能的成员数的情况下对伴随对象的apply
方法进行抽象 .你可以用一堆
CompanionN[A, B, C, ...]
特征手工完成这个,但这很烦人 . Shapeless提供了更好的解决方案,允许您编写如下内容:然后:
您可以这样使用:
您甚至可能不需要
CaseClassCompanion
部分,因为可以构造一个将元组转换为案例类的通用方法(假设成员类型对齐):然后:
这适用于最多包含22个成员的案例类(因为如果有超过22个参数,则无法将伴随对象上的
apply
方法扩展为函数) .问题是
apply
的签名因具体情况而异,并且这些功能没有共同特征 .Book.tupled
和Author.tupled
基本上具有相同的代码,但具有非常不同的签名 . 因此,解决方案可能不如我们所希望的那么好 .我可以设想一种使用注释宏来切割样板的方法 . 由于没有't a nice way to do it with the standard library, I' ll求助于代码生成(它仍具有编译时安全性) . 需要注意的是,注释宏需要使用macro paradise编译器插件 . 宏也必须位于单独的编译单元中(如另一个sbt子项目) . 使用注释的代码也需要使用宏天堂插件 .
用法:
或者,这样的事情可能是无形的 . 请参阅@ TravisBrown的更好答案 .