【问题标题】:implicit parameter VS default parameter value隐式参数 VS 默认参数值
【发布时间】:2014-01-31 12:22:16
【问题描述】:

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

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

【问题讨论】:

    标签: scala implicit


    【解决方案1】:

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

    1. 您不应该创建或使用一般类型的隐式参数,如IntString。请参阅下面的引文。
    2. 默认值是最简单的解决方案。就语言特征的复杂性而言。
    3. 隐式参数用于您的方法的某种“上下文”。如果没有上下文,只是默认值,你会迷惑其他开发者。
    4. 隐式值搜索会花费您一些编译时间。
    5. 应仅在极少数情况下手动指定隐式参数。

    另见:Programming In Scala 21.5 Implicit parameters/A style rule for implicit parameters:

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

    【讨论】:

    • 你能解释一下“上下文”这个词吗?与ThreadLocal 并列好吗?
    • 不完全是。例如看看withSession method in Slick。在implicit session => 之后,所有操作都将在此会话的上下文中执行。在Future 的情况下,所有操作(mapforeach 等)都应在ExecutionContext 范围内执行。
    • @YannMoisan:同样在scala.math.Ordering 的上下文中(import scala.math.Ordering._ 之后)集合将按字典顺序进行比较。
    【解决方案2】:

    其他答案很有趣,它们提出了隐含导致编译时间变慢和代码更复杂的有效点。

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

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

    当然,库可以提供将被其函数使用的隐式——你在 Scala 库中一直使用隐式,而不必定义它们,对吧?

    但是,当使用隐式时,调用者始终可以指定要使用的不同“默认值”。

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

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

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

    【讨论】:

    • you can use an implicit and a default at the same time 甚至隐含的默认值!
    【解决方案3】:

    如果您声明一个默认值,那么您将始终拥有相同的默认值。对于隐式,默认值将取决于函数的使用位置。 例如,如果你提供这样一个函数:

     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。

    【讨论】:

    猜你喜欢
    • 2012-04-30
    • 1970-01-01
    • 2012-03-14
    • 2013-08-21
    • 2021-10-27
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多