Scala隐式歧义示例修改不引发编译错误

时间:2019-07-16 22:03:40

标签: scala implicit

我正在尝试在Scala中实现隐式Not[T],因此,当类型T的范围中存在隐式val时,我想引发编译器错误。我想到了使用模棱两可的隐式方法进行此操作,因为Scaladoc展示了一种实现=!=的方法。 (请参见下文)

但是,我不明白为什么需要两个newAmbig,因为如果我删除一个=!=似乎仍然有一个模棱两可的隐含意义,因为最初似乎有3个可行的隐含意义。 (见下文)

我找不到有关编译器标记不明确的隐式内容所需的任何文档。

Scaladoc显示的trait =!=[C, D] implicit def neq[E, F] : E =!= F = null @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}") implicit def neqAmbig1[G, H, J] : J =!= J = null implicit def neqAmbig2[I] : I =!= I = null implicitly[Int =!= Int] 的实现:

=!=

trait =!=[C, D] implicit def neq[E, F] : E =!= F = null @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}") implicit def neqAmbig1[G, H, J] : J =!= J = null implicitly[Int =!= Int] 的实现似乎可行,但无效:

neqAmbig1

因为neqnull应该是同一类型,并且都应该找到。

但是,这不会引发编译器错误,并且在测试时仅返回myOtherStream.transform(() -> new MyTransformer<>(), MY_STORE) .leftJoin(myOtherKTable, new MyOtherValueJoiner<>(), Joined.with(JoinedKey.serde(), JoinedValue.serde(), JoinedValueOutput.serde()));

2 个答案:

答案 0 :(得分:2)

isAsSpecific似乎是编译器的相关部分,该代码整理了规范中的重载分辨率规则,因此请查看是否可以解密这些规则:

/** Is type `ftpe1` strictly more specific than type `ftpe2`
 *  when both are alternatives in an overloaded function?
 *  @see SLS (sec:overloading-resolution)
 */
 def isAsSpecific(ftpe1: Type, ftpe2: Type): Boolean

要确认您的第一个实现正确无误,请考虑{shape所提供的Type inequality

// Type inequalities
trait =:!=[A, B] extends Serializable
implicit def neq[A, B] : A =:!= B = new =:!=[A, B] {}
implicit def neqAmbig1[A] : A =:!= A = unexpected
implicit def neqAmbig2[A] : A =:!= A = unexpected

例如,

import shapeless.{<:!<, =:!=}

def foo[A](a: A)(implicit ev: A =:!= String): A = a

foo(3)  // ok
foo("") // error: ambiguous implicit values

答案 1 :(得分:2)

让我们从简化和澄清情况开始。

这有效。隐式已按预期解决。

trait =!=[C, D]

implicit def neq[E, F] : E =!= F =
  new =!=[E,F]{override def toString="NEQ"}

implicitly[Int =!= Int]  //res0: Int =!= Int = NEQ

现在让我们添加应该是一个模糊的隐式。

trait =!=[C, D]

implicit def neq[E, F] : E =!= F =
  new =!=[E,F]{override def toString="NEQ"}

implicit def neqAmbig1[E, F] : E =!= E =
  new =!=[E,E]{override def toString="NeqAm1"}

implicitly[Int =!= Int]  //res0: Int =!= Int = NeqAm1

嗯。对于Int =!= Int,我们将E设为Int,将F设为Int,因此类型E =!= F应该与{{ 1}},但是编译器并不认为它们是等效的,而是选择E =!= E版本(无论隐式代码中定义的顺序如何)。

我相信language spec中描述了这里发生的事情:

  

如果有多个与隐式参数类型匹配的合格参数,则将使用静态重载解析规则选择一个最具体的参数。

这来自“隐式参数”部分,但我认为它仍然适用:类型E =!= E比类型E =!= E更特定于Int =!= Int