scala - 创建一个模糊的低优先级隐式

标签 scala implicit scala-macros scala-compiler

考虑 io 中提供的默认编解码器包裹。

implicitly[io.Codec].name  //res0: String = UTF-8

这是一个隐含的“低优先级”,因此很容易覆盖而不会产生歧义。
implicit val betterCodec: io.Codec = io.Codec("US-ASCII")

implicitly[io.Codec].name  //res1: String = US-ASCII

提高其优先级也很容易。
import io.Codec.fallbackSystemCodec
implicit val betterCodec: io.Codec = io.Codec("US-ASCII")

implicitly[io.Codec].name  //won't compile: ambiguous implicit values

但是我们可以反其道而行之吗?我们可以创建一个低级别的隐式来禁用(“歧义”?)默认值吗?我一直在研究优先级方程并尝试使用低优先级的隐式,但我还没有创建一些对默认值不明确的东西。

最佳答案

如果我理解正确,您想在编译时检查是否存在本地隐式 io.Codec (“更高优先级”)或否则产生编译错误。这可以通过宏来完成(使用编译器内部)。

import scala.language.experimental.macros
import scala.reflect.macros.{contexts, whitebox}

object Macros {

  def localImplicitly[A]: A = macro impl[A]

  def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._

    val context = c.asInstanceOf[contexts.Context]
    val global: context.universe.type = context.universe
    val analyzer: global.analyzer.type = global.analyzer
    val callsiteContext = context.callsiteTyper.context

    val tpA = weakTypeOf[A]

    val localImplicit = new analyzer.ImplicitSearch(
      tree = EmptyTree.asInstanceOf[global.Tree],
      pt = tpA.asInstanceOf[global.Type],
      isView = false,
      context0 = callsiteContext.makeImplicit(reportAmbiguousErrors = true),
      pos0 = c.enclosingPosition.asInstanceOf[global.Position]
    ) {
      override def searchImplicit(
                                   implicitInfoss: List[List[analyzer.ImplicitInfo]],
                                   isLocalToCallsite: Boolean
                                 ): analyzer.SearchResult = {
        if (isLocalToCallsite)
          super.searchImplicit(implicitInfoss, isLocalToCallsite)
        else analyzer.SearchFailure
      }
    }.bestImplicit

    if (localImplicit.isSuccess)
      localImplicit.tree.asInstanceOf[c.Tree]
    else c.abort(c.enclosingPosition, s"no local implicit $tpA")
  }
}

localImplicitly[io.Codec].name // doesn't compile
// Error: no local implicit scala.io.Codec

implicit val betterCodec: io.Codec = io.Codec("US-ASCII")
localImplicitly[Codec].name // US-ASCII

import io.Codec.fallbackSystemCodec
localImplicitly[Codec].name // UTF-8

import io.Codec.fallbackSystemCodec
implicit val betterCodec: io.Codec = io.Codec("US-ASCII")
localImplicitly[Codec].name // doesn't compile
//Error: ambiguous implicit values:
// both value betterCodec in object App of type => scala.io.Codec
// and lazy value fallbackSystemCodec in trait LowPriorityCodecImplicits of type => //scala.io.Codec
// match expected type scala.io.Codec

在 2.13.0 中测试。
libraryDependencies ++= Seq(
  scalaOrganization.value % "scala-reflect" % scalaVersion.value,
  scalaOrganization.value % "scala-compiler" % scalaVersion.value
)

关于scala - 创建一个模糊的低优先级隐式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55462253/

相关文章:

Scala:已弃用集差的替代方案

java - 如果在 java 中传递整数值作为参数,则隐式类型转换不起作用

scala - 在需要它们的类型的继承者中提供隐式实例

c++ - 从模板基类派生的类的隐式转换

scala - 在运行时访问函数源代码的宏

scala - 函数式编程 : Curry & Fold - what are the etymologies?

eclipse - 如何添加新的 JVM 语言,例如Scala、Clojure、Fantom、Groovy 到 Eclipse IDE?

Scala 构造函数

Scala 宏 : Getting a List of TypeSymbols to be used at runtime

scala - 使用 Scala 的宏来强制类型相等