简体   繁体   English

类型,元组,隐式优先级和重载方法

[英]Types, Tuples, Implicit priority and Overloaded methods

Trying to disambiguate which method is called based upon the type of the second parameter, Any vs. Throwable, but without success. 试图消除根据第二个参数的类型(Any vs. Throwable)调用哪个方法的歧义,但没有成功。 Compiling the code below generates the following error message: 编译下面的代码会生成以下错误消息:

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

Here's the code: 这是代码:

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")
    }
  }
}

I tried making the "t2" lower priority as follows: 我试着将“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 {
    ....
 }

and removing "t2" from the "Call" object, but got the same error message. 并从“调用”对象中删除“t2”,但得到相同的错误消息。

I would like the disambiguation to take place at compile-time and not at run-time. 我希望消除歧义在编译时而不是在运行时进行。 Thanks. 谢谢。

Miles Sabin provided me with the following solution: Miles Sabin为我提供了以下解决方案:

    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")
        }
      }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM