在类体内隐式的解析

时间:2017-07-05 19:26:35

标签: scala

在高级别,我很想知道如何解决在类体内定义的隐含?我认为它们将被视为当前范围的一部分(根据令人敬畏的答案here),但我错了。

对于一个具体的例子,为什么不能以下工作:

trait Convert[T, U] { 
  final def value(record: T)(implicit f: T => U): U = f(record) 
}


case class ConvertMap(key: String) 
  extends Convert[Map[String, String], Boolean] { 
  implicit def a2b(m: Map[String, String]): Boolean = m.contains(key)
}

我可以实例化类ConvertMap,但是当我调用value方法时,我收到一条错误,指出Map [String,String] =>中的视图无法找到布尔值。

scala> val c = ConvertMap("key")
c: ConvertMap = ConvertMap(key)

scala> c.value(Map("key" -> "value"))
<console>:13: error: No implicit view available from Map[String,String] => Boolean.

2 个答案:

答案 0 :(得分:2)

如果您重新阅读为隐式解决范围提供的答案,您会发现此处发生了一些事情,导致您定义的隐式无法找到。

首先,如果在调用站点的本地范围内找不到隐式,我们将推迟“类别2”查找涉及隐式底层类型的含义。我们正在搜索Map[String, String] => Boolean类型的隐式转换。根据隐式范围规则,以下内容适用于我们的用例:

  
      
  • 如果T是参数化类型S[T1, ..., Tn],则ST1,...,Tn各部分的并集。
  •   

我们的S[T1.. Tn]Map[String, String](及其基类),因此我们将MapString都作为隐式查找的候选类型,但它们都不是保持转换。此外,还考虑了返回类型,这意味着Boolean也在范围内,但同样,它不包含隐式,因此编译器会抱怨。

可以帮助编译器找到它的最简单的事情是将隐式放在ConvertMap的伴随对象中,但这意味着我们不能再在构造函数中接受值key ,这让你的例子有点做作。

答案 1 :(得分:1)

它需要在呼叫站点(可以调用c.value时)进行解析。 那时,你在范围c中唯一拥有的东西。我不确定为什么你会认为在里面定义一个类的内容在那个时候被考虑在范围内。

顺便说一下,你的例子对于implicits来说似乎并不是很好用。为什么不让f成为特征中的成员方法?