是否有一种隐式获取对象实例的方法



我们想用无框的
创建一个任意Enumerations的编码器基本上是创建从任意EnumerationByte的双向映射。目前,我们的解决方案少是在我们的所有枚举实例上提供证据,以便Deserializer可以在该实例上访问并调用apply,这是一种从Byte创建Enumeration的方法。我们希望在不定义这些隐式值的情况下找到一种方法,而是让它们从E类型自动拾取。据我们所知,对象类型是与单个实例的一对S对应的,因此我们希望有一种机制可以做到这一点。

例如,以下工作

import frameless._
object Color extends Enumeration {
  type Color = Value
  val Red, Green, Blue = Value
}
object State extends Enumeration {
  type State = Value
  val Running, Stopped, Finished = Value
}
implicit val colorEvidence = Color // we want to spare these lines
implicit val stateEvidence = State // we want to spare these lines
implicit def enumToByteInjection[E <: Enumeration](implicit e: E): 
  Injection[E#Value, Byte] = Injection(_.id.toByte, e.apply(_))

解决方案1(反射(

使用scalac 2.12.4编译时,此处编译并运行:

object Color extends Enumeration {
  type Color = Value
  val Red, Green, Blue = Value
}
object State extends Enumeration {
  type State = Value
  val Running, Stopped, Finished = Value
}
/** Dummy replacement with similar signature */
class Injection[A, B]()

import scala.reflect.runtime.universe.TypeTag
object ItDoesNotWorkInReplObjectsMustBeTopLevel {
  implicit def enumToByteInjection[E <: Enumeration](implicit tt: TypeTag[E]): Injection[E#Value, Byte] = {
    val ru = scala.reflect.runtime.universe
    val classLoaderMirror = ru.runtimeMirror(getClass.getClassLoader)
    val moduleSymbol = ru.typeOf[E].termSymbol.asModule
    val moduleMirror = classLoaderMirror.reflectModule(moduleSymbol)
    val companionObject = moduleMirror.instance.asInstanceOf[E]
    println(s"/* 1 */ Materialize companion object $companionObject out of nothing!")
              /* 2 */ ???
              /* 3 */ // profit!
  }
  /** A function that requires implicit `Injection` */
  def testNeedsInjection[E <: Enumeration](implicit inj: Injection[E#Value, Byte]): Unit = 
    println("replace ??? above to continue here")

  def main(args: Array[String]): Unit = {
    /** Test whether an implicit injection is constructed */
    testNeedsInjection[Color.type] // compiles (crashes, as expected, but compiles)
  }
}

当然是因为???上缺少实现的崩溃,但是在之后,隐式伴随对象被召唤成存在。

gotchas:

  • 作为脚本运行时不起作用
  • 不起作用(需要对象成为顶级(
  • 确保您使用的是正确的classloader,提供诸如classOf[Unit].classLoader之类的东西导致NoSuchClassExceptions。
  • 需要枚举的TypeTag s(与 concrete 枚举一起使用时,不应该是问题但是仍然有"访问表面":然后,您必须通过每种方法将TypeTag s拉到表面(。

解决方案2(隐式对象(

如果您控制了所有枚举,则可以简单地声明枚举对象本身implicit。以下编译很好,所有隐含的插入都按预期插入:

implicit object Color extends Enumeration {
  type Color = Value
  val Red, Green, Blue = Value
}
implicit object State extends Enumeration {
  type State = Value
  val Running, Stopped, Finished = Value
}
/** Dummy replacement with similar signature */
class Injection[A, B]()
implicit def enumToByteInjection[E <: Enumeration](implicit e: E): Injection[E#Value, Byte] = ???
/** A function that requires implicit `Injection` */
def needsInjection[E <: Enumeration](implicit inj: Injection[E#Value, Byte]): Unit = ???
/** Test whether an implicit injection is constructed */
needsInjection[Color.type] // compiles (crashes, as expected, but compiles)

解决方案3(无形魔法(

我们还可以使用无形的Witness ES来召唤我们的枚举类型的单例值。无形使用编译时间反射和代码生成来为给定类型创建实例。

import shapeless._
implicit def enumToByteInjection[E <: Enumeration](implicit w: Witness.Aux[E]):
  Injection[E#Value, Byte] = Injection(_.id.toByte, w.value.apply(_))

相关内容

  • 没有找到相关文章

最新更新