scala - 使用 shapeless.Generic 时,如何避免错误“超级构造函数不能传递自引用,除非参数是按名称声明的”?
问题描述
在现成的 scala 2.12 和 shapeless 2.3.2 下,以下简单程序无法编译:
import shapeless.Generic
object InferGeneric {
class WithGeneric[T](implicit ev: Generic[T])
case class Impl() {}
object Impl extends WithGeneric[Impl]
}
编译器抛出以下错误:
/.../InferGeneric.scala:11: super constructor cannot be passed a self reference unless parameter is declared by-name
object Impl extends WithGeneric[Impl]
有趣的是,当object Impl
被重命名时,它可以毫无问题地编译。看起来通用推理中使用的宏在与伴随对象组合时会导致一些循环解析。如何避免这种情况?
非常感谢您的意见!
解决方案
问题是宏生成的代码,但它并不是真正特定于宏的。您可以使用明确定义的实例重现该问题:
import shapeless._
class WithGeneric[T](implicit ev: Generic[T])
case class Impl()
object Impl extends WithGeneric[Impl]()(
new Generic[Impl] {
type Repr = HNil
def to(p: Impl): Repr = HNil
def from(p: Repr): Impl = Impl()
}
)
或者,如果您想确保不涉及宏:
trait Generic[A] { def mk: A }
class WithGeneric[T](ev: Generic[T])
case class Impl()
object Impl extends WithGeneric[Impl](
new Generic[Impl] { def mk: Impl = Impl() }
)
通常,在实例化伴随对象时,您将无法传递Impl.apply
在构造函数调用中调用的代码。Impl
如果不了解更多有关您要使用的内容,很难提出解决方法WithGeneric
。在像这样的简单情况下,您可以Generic[Impl]
显式定义并且只使用new Impl
构造函数(不是Impl.apply
)。如果您想要的是能够为伴随对象的便利方法提供对案例类进行抽象的定义,您可以执行以下操作:
import shapeless._
abstract class WithGeneric[T] {
def ev: Generic[T]
}
case class Impl()
object Impl extends WithGeneric[Impl] {
def ev: Generic[Impl] = Generic[Impl]
}
这是一个小样板,但在不了解您的用例的情况下,我猜这可能是您最好的选择。
推荐阅读
- asp.net-core - 如何在 asp.net 核心应用程序的配置中为 docker-compose vars 使用 .env 文件?
- android - Cordova android 加载资源失败:net::ERR_FILE_NOT_FOUND
- javascript - 在 mozilla 和 chrome 浏览器中自动启用网络摄像头
- sql - 不使用内部联接的 Sql 查询
- artisan-migrate - Migration Command issue
- python - 如何识别有关考试成绩的列数据中的异常值并返回异常值的国家/地区名称
- c# - 是否可以在 .net mvc 和 c# 的静态道具中维护聊天消息?
- docker - Re using existing volume at docker-compose ELK stack
- asp.net-identity - ASP.Net Core Identity - 加入多个Authroize-Attr
- docker - 当运行错误代码 139 时,docker 立即退出