使用shapeless.Generic时,如何避免错误'super constructor cannot be passed a self reference unless parameter is declared by-name'?

When using shapeless.Generic, how to avoid the error 'super constructor cannot be passed a self reference unless parameter is declared by-name'?

下面的简单程序在现成的 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]
}

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