为什么隐式参数的顺序有时很重要?

Why does the order of implicit parameters sometimes matter?

关于以下代码段 (scala 2.12.10),我的问题是为什么在特定情况下顺序对于隐式参数很重要。我也不明白为什么编译器告诉我存在不明确的隐式值,我看到了任何关于它的提示。

import scala.reflect.ClassTag

trait Wrapper[T] {

  implicit def ct: ClassTag[T]

  // First try using scala syntaxic sugar for single type parameter type class
  def asPair1[K : ClassTag, V : ClassTag](implicit ev: T <:< (K, V)): Unit = Unit
  
  // Same as asPair1 with explicit implicits ClassTag, in same order than with syntaxic sugar version
  def asPair1Bis[K, V](implicit kt: ClassTag[K], vt: ClassTag[V], ev: T <:< (K, V)): Unit = Unit

  // Workaround
  def asPair2[K, V](implicit ev: T <:< (K, V), kt: ClassTag[K], vt: ClassTag[V]): Unit = Unit
  
}

trait Test[K, V] {
  
  implicit def kt: ClassTag[K]
  implicit def vt: ClassTag[V]
  
  val w: Wrapper[(K, V)]
  
  w.asPair1  // Fails
/**
error: ambiguous implicit values:
 both method kt in trait Test of type => reflect.this.ClassTag[K]
 and method vt in trait Test of type => reflect.this.ClassTag[V]
 match expected type reflect.this.ClassTag[K]
    w.asPair1  // Fails
      ^
error: No ClassTag available for K
    w.asPair1  // Fails
      ^
error: not enough arguments for method asPair1: (implicit   evidence: reflect.this.ClassTag[K], implicit   evidence: reflect.this.ClassTag[V], implicit  ev: $less$colon$less[scala.this.Tuple2[K,V],scala.this.Tuple2[K,V]])scala.this.Unit.
Unspecified value parameters evidence, evidence, ev.
    w.asPair1  // Fails
*/

  w.asPair1Bis // Fails
  w.asPair2  // Works


  val w2: Wrapper[(Int, Double)]
  w2.asPair1 // Fails with exact same logs than with `w`
  w2.asPair2


}

所以首先,不要混合上下文边界和隐式,这被认为是一种不好的做法;有关更多上下文,请参阅 this

其次,顺序很重要,因为如果 ev 先出现,那么类型参数 KV 会在编译器尝试搜索它们的 ClassTags.
在另一种情况下,编译器没有关于 KV 是什么的信息,所以它会尝试假设它能找到的任何东西,从而找到两个可能的 implicit ClassTags (外部K和外部V造成歧义。