2011-10-15 37 views
5

試圖根據第二個參數Any vs. Throwable的類型來調用哪個方法,但沒有成功。編譯下面的代碼生成以下錯誤消息:類型,元組,隱式優先級和重載方法

Main.scala:85: error: ambiguous reference to overloaded definition, 
both method apply in class Call of type (body: =>(String, Throwable, Array[Any]))(implicit m: Main.Call.Dummy3)Unit 
and method apply in class Call of type (body: => (String, Array[Any]))(implicit m: Main.Call.Dummy1)Unit 
match argument types ((String, Throwable, String)) 
    agent.call { 
     ^
one error found 

下面的代碼:

object Main { 
    object Call { 
    implicit def t1(t: Tuple2[String, Any]): Tuple2[String, Array[Any]] = { 
     (t._1, Array(t._2)) 
    } 
    implicit def t1t(t: Tuple2[String, Throwable]): Tuple2[String, Throwable] = { 
     (t._1, t._2) 
    } 
    implicit def t2(t: Tuple3[String, Any, Any]): Tuple2[String, Array[Any]] = { 
     (t._1, Array(t._2, t._3)) 
    } 
    implicit def t2t(t: Tuple3[String, Throwable, Any]): Tuple3[String, Throwable, Array[Any]] = { 
     (t._1, t._2, Array(t._3)) 
    } 

    class Dummy1 
    object Dummy1 { 
     implicit def dummyImplicit: Dummy1 = { 
println("Dummy1.dummyImplicit") 
     new Dummy1 
     } 
    } 
    class Dummy2 
    object Dummy2 { 
     implicit def dummyImplicit: Dummy2 = { 
println("Dummy2.dummyImplicit") 
     new Dummy2 
     } 
    } 
    class Dummy3 
    object Dummy3 { 
     implicit def dummyImplicit: Dummy3 = { 
println("Dummy3.dummyImplicit") 
     new Dummy3 
     } 
    } 
    } 
    import Call._ 

    class Call { 

    def apply(body: => Tuple2[String, Array[Any]]) 
     (implicit m: Dummy1): Unit = { 
     println("message and array of parameters") 
    } 
    def apply(body: => Tuple2[String, Throwable]) 
     (implicit m: Dummy2): Unit = { 
     println("message and throwable") 
    } 
    def apply(body: => Tuple3[String, Throwable, Array[Any]]) 
     (implicit m: Dummy3): Unit = { 
     println("message, throwable and array of parameters") 
    } 
    } 

    class Agent { 
    val _call = new Call 
    def call: Call = _call 
    } 

    def main(args: Array[String]): Unit = { 
    val msg = "XXX" 
    val agent = new Agent 
    agent.call { 
     (msg, "one") 
    } 
    agent.call { 
     (msg, new Exception) 
    } 
    agent.call { 
     (msg, "one", "two") 
    } 
    agent.call { 
     (msg, new Exception, "one") 
    } 
    } 
} 

我試圖使得 「T2」 較低優先級如下:

trait LowPriority { 
    implicit def t2(t: Tuple3[String, Any, Any]): Tuple2[String, Array[Any]] = { 
     (t._1, Array(t._2, t._3)) 
    } 
} 
object Call extends LowPriority { 
    .... 
} 

和去除「 t2「來自」Call「對象,但得到相同的錯誤信息。

我想消除歧義發生在編譯時,而不是在運行時。 謝謝。

回答

2

萬里薩賓給我提供了以下解決方案:

object Main { 

     object Call { 
     trait LowPriorityDistinguishThrowable { 
      trait Wrap1[A, B] { 
      val body : (A, B) 
      def apply(call: Call) : Unit 
      } 
      trait Wrap2[A, B, Any] { 
      val body : (A, B, Any) 
      def apply(call: Call) : Unit 
      } 

      implicit def wrap11[T](body0 : => (String, T)) = 
      new Wrap1[String, T] { 
       lazy val body = body0 
       def apply(call: Call) { 
       println("(message and not throwable): " +body) 
       } 
      } 

      implicit def wrap21[T](body0 : => (String, T, Any)) = 
      new Wrap2[String, T, Any] { 
       lazy val body = body0 
       def apply(call: Call) { 
       println("(message and not throwable): " +body) 
       } 
      } 
     } 

     object DistinguishThrowable extends LowPriorityDistinguishThrowable { 
      implicit def wrap12(body0 : => (String, Throwable)) = 
      new Wrap1[String, Throwable] { 
       lazy val body = body0 
       def apply(call: Call) { 
       println("(message and throwable): " +body) 
       } 
      } 

      implicit def wrap22(body0 : => (String, Throwable, Any)) = 
      new Wrap2[String, Throwable, Any] { 
       lazy val body = body0 
       def apply(call: Call) { 
       println("(message and throwable): " +body) 
       } 
      } 
     } 
     } 

     class Call(val enabled: Boolean) { 
     import Call._ 
     import DistinguishThrowable._ 

     def apply[T](body: Wrap1[String, T]): Unit = { 
      if (enabled) body(this) 
     } 
     def apply[T](body: Wrap2[String, T, Any]): Unit = { 
      if (enabled) body(this) 
     } 
     } 

     def main(args : Array[String]): Unit = { 
     val call = new Call(true) 

     call { 
      ("foo", new Exception) 
     } 
     call { 
      ("foo", "bar") 
     } 

     call { 
      ("foo", new Exception, "one") 
     } 
     call { 
      ("foo", "bar", "one") 
     } 
     } 
    }