【问题标题】:Scala Named ArgumentsScala 命名参数
【发布时间】:2013-12-18 03:06:32
【问题描述】:

我正在查看Scala in Depth 中的这个Named Arguments 示例:

scala> class Parent {
     | def foo(bar: Int = 1, baz: Int = 2): Int = bar + baz
     | }
defined class Parent

scala> class Child extends Parent {
     |    override def foo(baz: Int = 3, bar: Int = 4): Int = super.foo(baz, bar)
     | }
defined class Child

scala> val p = new Parent
p: Parent = Parent@6100756c

scala> p.foo()
res1: Int = 3

scala> val x = new Child
x: Child = Child@70605759

调用 x.foo() 的结果为 7,因为 Child#foo 的默认参数为 3 和 4。

scala> x.foo()
res3: Int = 7

在运行时实例化一个新的Child,但在编译时实例化Parent这可能正确也可能不正确

scala> val y: Parent = new Child
y: Parent = Child@540b6fd1

调用 x.foo() 计算结果为 7,因为 Child#foo 的默认参数为 3 和 4。

scala> y.foo()
res5: Int = 7

调用 x.foo() 的结果为 4,因为 Child#foo 的默认 baz 参数为 3。

scala> x.foo(bar = 1)
res6: Int = 4

但是,我不明白为什么 y.foo(bar = 1) 返回 5。我希望 Child#foo 会被评估,因为 yChild 类型。将1的bar传入foo意味着baz的默认值为3。所以它应该产生4。但我的理解当然是不正确的。

scala> y.foo(bar = 1)
res7: Int = 5

【问题讨论】:

    标签: scala


    【解决方案1】:

    有两个原因:

    默认参数实现

    scala 编译器为默认参数创建辅助方法:

    val p = new Parent()
    val c = new Child()
    
    p.`foo$default$1`
    // Int = 1
    p.`foo$default$2`
    // Int = 2
    
    c.`foo$default$1`
    // Int = 3
    c.`foo$default$2`
    // Int = 4
    

    这就是为什么您不仅可以使用常量,还可以使用默认参数的字段和方法:

    def test(i: Int = util.Random.nextInt) = i
    
    test()
    // Int = -1102682999
    
    test()
    // Int = -1994652923
    

    命名参数实现

    编译后没有命名参数 - 所有参数都是位置参数。

    所以由于barChild#foo 的第二个参数,这段代码:

    c.foo(bar = 1)
    // Int = 4
    

    被编译器翻译成这样:

    c.foo(c.`foo$default$1`, /*bar = */1)
    // Int = 4
    

    但由于barParent#foo 的第一个参数,此代码:

    val tmp: Parent = c
    tmp.foo(bar = 1)
    // Int = 5
    

    翻译成这样:

    tmp.foo(/*bar = */1, tmp.`foo$default$2`)
    // Int = 5
    

    我们已经知道 c.foo$default$2 返回 4,所以 c.foo(1, 4) 返回 5。

    【讨论】:

    • 所以tmp使用Parent的签名(bar and baz), but the default values of Child`的位置?
    • @KevinMeredith,实际上foo$default$2Parent 的方法被Child 覆盖。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-30
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    • 1970-01-01
    相关资源
    最近更新 更多