Scala命名为参数

 呼吸乱了的声音_648 发布于 2023-02-09 15:44

Named Arguments在Scala中深入研究这个例子:

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()由于Child#foo默认参数为3和4,因此调用求值为7 .

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

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

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

x.foo()由于Child#foo默认参数为3和4,因此调用求值为7 .

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

x.foo()由于Child#foo默认baz参数为3,因此调用计算结果为4 .

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

但是,我不明白为什么会y.foo(bar = 1)返回5.我会期望Child#foo被评估,因为它y是一种Child类型.传入bar1的a foo表示baz默认值为3.因此它应该产生4.但我的理解当然是不正确的.

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

senia.. 7

有两个原因:

默认参数实现

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.

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.

    2023-02-09 15:47 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有