创建一个含糊的低优先级隐式 [英] create an ambiguous low priority implicit

查看:100
本文介绍了创建一个含糊的低优先级隐式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑io软件包中提供的默认编解码器.

Consider the default codec as offered in the io package.

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

它是隐式的低优先级",因此很容易将其覆盖而不会产生歧义.

It's a "low priority" implicit so it's easy to override without ambiguity.

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

但是我们可以朝相反的方向走吗?我们可以创建一个低级别的隐式来禁用(歧义化")默认值吗?我一直在研究优先级方程式,并使用低优先级隐式变量进行操作,但尚未创建与默认值不明确的内容.

But can we go in the opposite direction? Can we create a low level implicit that disables ("ambiguates"?) the default? I've been looking at the priority equation and playing around with low priority implicits but I've yet to create something ambiguous to the default.

推荐答案

如果我正确理解,您想在编译时检查是否存在局部隐式io.Codec(高优先级"),否则会产生编译错误.可以使用宏(使用编译器内部函数)完成此操作.

If I understand correctly you want to check at compile time that there is local implicit io.Codec ("higher-priority") or produce compile error otherwise. This can be done with macros (using compiler internals).

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中进行了测试.

Tested in 2.13.0.

libraryDependencies ++= Seq(
  scalaOrganization.value % "scala-reflect" % scalaVersion.value,
  scalaOrganization.value % "scala-compiler" % scalaVersion.value
)

这篇关于创建一个含糊的低优先级隐式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆