简体   繁体   English

在Scala中定义具有多个隐式参数的函数

[英]Defining a function with multiple implicit arguments in Scala

如何定义具有多个隐式参数的函数。

def myfun(arg:String)(implicit p1: String)(implicit p2:Int)={} // doesn't work

它们必须全部放在一个参数列表中,并且该列表必须是最后一个。

def myfun(arg:String)(implicit p1: String, p2:Int)={} 

There actually is a way of doing exactly what the OP requires. 实际上,有一种方法可以完全满足OP的要求。 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 (aka "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. 在Scala 3中(也就是“ Dotty”,尽管这是编译器的名称),而不是返回辅助MyFunPart2对象,可以直接返回带有隐式参数的函数值。 This is because Scala 3 supports "Implicit Functions" (ie "parameter implicitness" now is part of function types). 这是因为Scala 3支持“隐式函数”(即“参数隐式”现在是函数类型的一部分)。 Multiple implicit parameter lists become so easy to implement that it's possible the language will support them directly, though I'm not sure. 多个隐式参数列表变得如此易于实现,以至于该语言有可能直接支持它们,尽管我不确定。

There is another (IMO simpler and more flexible) way to achieve a similar effect: 还有另一种(IMO更简单,更灵活)的方式来达到类似的效果:

// 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. 一个重要的优点是,可以给它们指定比_1和_2更有意义的名称。

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

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