Scala命名参数

Scala命名参数,scala,Scala,我正在看下面的命名参数示例: 调用x.foo()的计算结果为7,因为Child\foo的默认参数为3和4 scala> x.foo() res3: Int = 7 scala> y.foo() res5: Int = 7 在运行时实例化一个新的子级,但在编译时实例化父级。这可能正确,也可能不正确 调用x.foo()的计算结果为7,因为Child\foo的默认参数为3和4 scala> x.foo() res3: Int = 7 scala> y.foo() res5

我正在看下面的
命名参数
示例:

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

scala> x.foo()
res3: Int = 7
scala> y.foo()
res5: Int = 7
在运行时实例化一个新的
子级
,但在编译时实例化父级
。这可能正确,也可能不正确

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

scala> x.foo()
res3: Int = 7
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
进行评估,因为
y
Child
类型。将
bar
的值1传递到
foo
表示
baz
的默认值为3。所以它应该产生4。但我的理解当然是错误的

scala> y.foo(bar = 1)
res7: Int = 5
原因有二:

默认参数实现
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
这就是为什么您不仅可以使用常量,还可以使用字段和方法作为默认参数:

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
命名参数实现 编译后没有命名参数-所有参数都是位置参数

因此,由于
bar
Child#foo
此代码的第二个参数:

c.foo(bar = 1)
// Int = 4
val tmp: Parent = c
tmp.foo(bar = 1)
// Int = 5
由编译器转换为:

c.foo(c.`foo$default$1`, /*bar = */1)
// Int = 4
但是由于
bar
Parent#foo
此代码的第一个参数:

c.foo(bar = 1)
// Int = 4
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。

so
tmp
使用
父项的签名(条和
baz
的位置),但是
子项的默认值?@KevinMeredith,实际上
foo$default$2
Parent
的方法被
Child
覆盖。