使用无形时。泛型,如何避免错误"除非按名称声明参数,否则无法传递超级构造函数自引用"?



以下简单程序无法编译,在现成的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伴随对象时,您将无法传递在构造函数调用中调用Impl.apply的代码。

如果不了解有关您要尝试使用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]
}

这是一个小样板,但在不了解您的用例的情况下,我的猜测可能是您最好的选择。

最新更新