Scala子类构造器能否调用父类字段?编译报错问题咨询
Scala case class构造器默认值引用父类成员的问题分析
错误原因
你遇到的编译错误,核心原因是Scala中case class构造器参数的默认值是在类定义的外部作用域求值的,而非实例构造阶段。
当你写barValue = s"${super.value1} ${super.value2}"时,这个默认值表达式会在Bar类被定义的上下文里先计算,此时既没有Bar的实例,super也只能指向Scala的根父类AnyRef——而AnyRef根本没有value1、value2这些成员,编译器自然会报错value barValue is not a member of AnyRef。
哪怕你把super换成this也没用,因为默认值求值时,实例还未创建,无法引用实例级别的成员。
可行的解决方法
方法1:将父类成员移至伴生对象(推荐)
把trait里的常量放到伴生对象中,让构造器默认值直接引用静态常量:
sealed trait Foo { import Foo._ val value1 = VALUE1 val value2 = VALUE2 } object Foo { val VALUE1 = "something" val VALUE2 = "else" } case class Bar(barValue: String = s"${Foo.VALUE1} ${Foo.VALUE2}") extends Foo
方法2:用伴生对象的apply方法实现默认逻辑
保留原trait结构,通过伴生对象的apply方法提供默认实例:
sealed trait Foo { val value1 = "something" val value2 = "else" } case class Bar private (barValue: String) extends Foo object Bar { // 默认构造逻辑,使用父类成员拼接值 def apply(): Bar = { val foo = new Foo {} new Bar(s"${foo.value1} ${foo.value2}") } // 保留自定义参数的构造入口 def apply(barValue: String): Bar = new Bar(barValue) }
方法3:保留case class结构的简化实现
如果不需要隐藏主构造器,也可以直接在伴生对象中提供无参apply方法:
sealed trait Foo { val value1 = "something" val value2 = "else" } case class Bar(barValue: String) extends Foo object Bar { def apply(): Bar = Bar(s"${new Foo {}.value1} ${new Foo {}.value2}") }
内容的提问来源于stack exchange,提问作者Ostap Strashevskii
相关产品推荐
相关产品推荐

