在 Scala 中定义具有多个隐式参数的函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10635406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Defining a function with multiple implicit arguments in Scala
提问by Ali Salehi
How can I define a function with multiple implicit arguments.
如何定义具有多个隐式参数的函数。
def myfun(arg:String)(implicit p1: String)(implicit p2:Int)={} // doesn't work
回答by missingfaktor
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)={}
回答by Mario Rossi
There actually is a way of doing exactly what the OP requires. A little convoluted, but it works.
实际上有一种方法可以完全满足 OP 的要求。有点复杂,但它有效。
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 MyFunPart2object, 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.
在 Scala 3(又名“Dotty”,尽管这是编译器的名称)中,不是返回辅助MyFunPart2对象,而是可以直接返回带有隐式参数的函数值。这是因为 Scala 3 支持“隐式函数”(即“参数隐式”现在是函数类型的一部分)。多个隐式参数列表变得如此容易实现,以至于语言可能会直接支持它们,尽管我不确定。
回答by Mario Rossi
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 更有意义的名称。

