Scala的隐式方法的参数不确定性消除

问题描述:

我不太明白下面的代码:Scala的隐式方法的参数不确定性消除

object M { 
    implicit object AMarker 
    implicit object BMarker 

    def m(ints: Seq[Int])(implicit i: AMarker.type): Unit = { 
    println(s"int seq $ints"); 
    } 

    def m(strs: Seq[String])(implicit s: BMarker.type): Unit = { 
    println(s"string seq $strs") 
    } 
} 

import M._ 

m(Seq(1, 2, 3)) 
m(Seq("a", "b", "c")) 

如果不是因为这两个标记,它不能编译,因为这两个m方法具有类型后,相同的签名擦除。

但是,我不明白什么是链接AMarkerSeq[Int],BMarkerSeq[String]的“魔术”。

更具体地说,当我打电话给m(Seq("a", "b"))时,编译器如何知道它应该使用隐含的BMarker,并调用第二个mSeq已经被删除了吗?

+3

由于Seq [A]的类型信息在编译时可用于调用正确的方法,但该信息在运行时不可用 – Falmarri

+2

不是您的问题的答案,而是一个有趣的观察:您还可以消除不明确性通过创建一个'm()'函数并将另一个作为方法。没有暗示或标记需要。 – jwvh

要直接回答您的问题,不,类型删除尚未发生。隐式搜索必须在充分了解类型的情况下才能发生。要了解这些方法如何看待在运行时,可以运行javap看到编译的类:

scala> :javap M -s 
Compiled from "<console>" 
public class M$ { 
    public static final M$ MODULE$; 
    Signature: LM$; 
    public static {}; 
    Signature:()V 

    public void m(scala.collection.Seq<java.lang.Object>, M$AMarker$); 
    Signature: (Lscala/collection/Seq;LM$AMarker$;)V 

    public void m(scala.collection.Seq<java.lang.String>, M$BMarker$); 
    Signature: (Lscala/collection/Seq;LM$BMarker$;)V 

    public M$(); 
    Signature:()V 
} 

所以基本上编译器取得了明确的运行方式。它在编译期间查找确切的方法,并基本上使用隐式对象来消除歧义。

酷招BTW!我还没有看到它以前用过这种方式。