隐含参数VS默认参数值

时间:2014-01-31 12:22:17

标签: scala implicit

Scala中至少有两种技术可以将默认值传递给方法

1)默认参数值

scala> def f(i: Int = 0) = i
f: (i: Int)Int

scala> f()
res0: Int = 0

scala> f(1)
res1: Int = 1

2)隐含参数

scala> def g(implicit i: Int) = i
g: (implicit i: Int)Int

scala> implicit val default = 0
default: Int = 0

scala> g(1)
res5: Int = 1

scala> g
res7: Int = 0

在哪种情况下你选择一个或另一个? 凭借隐式的力量,默认值是一个有用的功能吗?

3 个答案:

答案 0 :(得分:12)

你绝对应该更喜欢默认参数值。

  1. 您永远不应创建或使用IntString等常规类型的隐式参数。见下面的引文。
  2. 默认值是最简单的解决方案。在语言功能方面的复杂性。
  3. 隐式参数适用于您的方法的某种“上下文”。如果没有上下文,只需默认值就可以让其他开发人员感到困惑。
  4. 隐式值搜索会花费您一定的编译时间。
  5. 只应在极少数情况下手动指定隐式参数。
  6. 另请参阅:Programming In Scala 21.5 Implicit parameters/A style rule for implicit parameters

      

    作为样式规则,最好在隐式参数的类型中使用自定义命名类型。

答案 1 :(得分:8)

其他答案很有意思,它们提出了有效点,暗示了编译时间变慢和代码更复杂。

但是,我认为重要的是要理解,从某种意义上说,隐含和默认是互补的:

  • 使用默认值时,默认值由被调用者定义;
  • 使用implicits,默认值由调用者定义。

当然,库可能会提供其函数将使用的含义 - 您在Scala库中始终使用implicits而不必定义它们,对吗?

然而,当使用implicits时,调用者总是可以指定不同的"默认"使用。

在任何一种情况下,都可以在调用函数时显式传递该值。

另一个小的区别是,人们可以选择通过命名参数覆盖哪些默认值,但如果您选择明确传递一个默认值,则必须传递所有默认值。

最后,请注意您可以同时使用隐式和默认值。

答案 2 :(得分:1)

如果声明默认值,那么您将始终拥有相同的默认值。使用implicits,默认值将取决于函数的使用位置。 例如,如果您提供这样的功能:

 def listen(host:String, port:Int = 26000){ ...}

如果没有指定,使用此功能的人将侦听端口26000。 使用implicits,此函数的用户可以为该值定义自己的默认值:

//imagine this is defined in a library 
def listen(host:String, implicit port: Int ) { .. }  

//this is your code which uses that library 
implicit val port = 410000
...
listen("localhost")   //will use 41000

现在,在另一个包上,您可以使用不同的隐式:

implicit val port = 15000
listen("localhost")   //will use 150000

这样,您可以使您的功能更加灵活,但这一切都取决于能否覆盖该值是否有意义。

您也可以将两者结合起来:

def f(implicit i: Int = 260000)

这将使用隐式值(如果可用)或默认值为26000(如果没有)。