Defining a function with multiple implicit arguments in Scala

后端 未结 3 1442
[愿得一人]
[愿得一人] 2021-01-30 12:36

How can I define a function with multiple implicit arguments.

def myfun(arg:String)(implicit p1: String)(implicit p2:Int)={} // doesn\'t work
相关标签:
3条回答
  • 2021-01-30 12:40

    They must all go in one parameter list, and this list must be the last one.

    def myfun(arg:String)(implicit p1: String, p2:Int)={} 
    
    0 讨论(0)
  • 2021-01-30 12:44

    There is another (IMO simpler and more flexible) way to achieve a similar effect:

    // Note the implicit is now a Tuple2
    def myFun(arg: String)(implicit p: (String, Int) ): Unit = {
      println(arg + p._1 + p._2)
      /*otherwise your actual code*/
    }
    
    // These implicit conversion are able to produce the basic implicit (String,Int) Tuples
    implicit def idis(implicit is: String, ii: Int): (String,Int)= (is,ii)
    implicit def idi(s: String)(implicit ii: Int): (String,Int)= (s,ii)
    
    // The basic implicit values for both underlying parameters
    implicit val iString = " world! "
    implicit val iInt = 2019
    
    myFun("Hello")
    myFun("Hello")(" my friend! ")
    myFun("Hello")(" my friend! ",2020)
    
    // Output is:
    //     Hello world! 2019
    //     Hello my friend! 2019
    //     Hello my friend! 2020
    
    // If we add the following implicit, 
    implicit def ids(i: Int)(implicit is: String)= (is,i)
    
    // we can even do
    myFun("Hello")(2020)
    
    // , and output is:
    //     Hello world! 2020
    

    Using a Tuple as the underlying representation for the parameters is not a good idea because the implicit conversions could interfere with other uses. Actually, implicit conversions to any standard type (including library ones) usually create trouble in any non-trivial application. The solution is to create a dedicated case class to hold the parameters instead of a Tuple. An important advantage is that they could be given names much more meaningful than _1 and _2.

    0 讨论(0)
  • 2021-01-30 13:03

    There actually is a way of doing exactly what the OP requires. A little convoluted, but it works.

    class MyFunPart2(arg: String, /*Not implicit!*/ p1: String) {
      def apply(implicit p2: Int) = {
        println(arg+p1+p2)
        /* otherwise your actual code */
      }
    }
    
    def myFun(arg: String)(implicit p1: String): MyFunPart2= {
      new MyFunPart2(arg, p1)
    }
    
    implicit val iString= " world! "
    implicit val iInt= 2019
    
    myFun("Hello").apply
    myFun("Hello")(" my friend! ").apply
    myFun("Hello")(" my friend! ")(2020)
    
    //  Output is:
    //      Hello world! 2019
    //      Hello my friend! 2019
    //      Hello my friend! 2020
    

    In Scala 3 (a.k.a. "Dotty", though this is the compiler's name) instead of returning an auxiliary MyFunPart2 object, it's possible to return a function value with implicit arguments directly. This is because Scala 3 supports "Implicit Functions" (i.e. "parameter implicitness" now is part of function types). Multiple implicit parameter lists become so easy to implement that it's possible the language will support them directly, though I'm not sure.

    0 讨论(0)
提交回复
热议问题