【问题标题】:case class inheriting another class/trait案例类继承另一个类/特征
【发布时间】:2019-05-28 15:11:03
【问题描述】:

我想让一个案例类扩展一个特征

这是我的要求:

  1. 我需要为孩子使用案例类。这是一个硬性要求,因为 scopt (https://github.com/scopt/scopt)
  2. 父母需要是一个特质。很抱歉之前没有说清楚
  3. 我希望孩子可以访问父特征的属性,并且最好在声明子案例类时不必再次指定它们。例如,如果父特征是:trait ParentParams { var name: String = "Al" },那么子特征不应该是 case class ChildParams(id: String = "whatever", override val name: String = Parent.defaultName) extends Parent。我宁愿把它写成case class Child(id: String) extends Parent。但是,当我尝试第二种方法时,当我尝试对案例类对象执行 .copy() 时,我无法访问名称字段。作为一种解决方法,我可以通过childObj.name = "newName" 改变name 属性的值
  4. 我应该(硬要求)能够覆盖子对象从父对象继承的属性值。现在这是可能的,因为我已将父属性声明为 var 而不是 val。但是,理想情况下,我想让它不可变并使用复制方法来更改值。

这是我现在拥有的,但我无法使用.copy() 方法来更改继承属性的值。

package abcd.wxyz

import org.scalatest.{FlatSpec, Matchers}

trait ParentTrait {
  var name: String = "name"
}

case class TestParams(param1: String = "123") extends ParentTrait

class TestParamsSpec extends FlatSpec with Matchers {
  "TestParams" should "be able to access it's inherited attributes and modify them" in {

    val testParams = TestParams()
    testParams.name = "newName1"
    testParams.param1 should equal("123")
    testParams.name should equal("newName1")

    val modifiedTestParams = testParams.copy(name = "newName2") // cannot resolve symbol name
    modifiedTestParams.name should equal("newName2")

  }
}

对于上面的代码,我在 .copy(name = "newName2") 上收到“无法解析符号名称”。

拥有这种继承的原因是有一个函数接受一个子对象并期望它定义一个“名称”属性。例如,考虑一个将附加“先生”的函数。或“夫人”给定一个具有 name 属性的 Child 对象。

正在发生的事情的总体背景: 我正在使用 scopt 使用命令行输入值(进入案例类)填充配置。如果未提供任何值,则为该属性使用默认值。属性是指案例类中的数据成员。 我有一个函数(我们称之为 dbReader),它接受案例类的对象并使用它来建立连接并从数据库中读取。我的项目中有许多不同的参数案例类,我希望这些参数中的每一个都实现一个常见的DatabaseConnectionParameters 特征,以便函数 dbReader 可以工作,而不管传递给它的参数案例类。

【问题讨论】:

  • 我不明白你的问题。你希望这如何工作? case class Child(id: String = "55", override val name: String = super.name) 它没有扩展 Parent,即使它会这样做,如果您需要在构造时传递该名称,您希望如何使用父级的 name? - 我相信,这是一个 XY 问题,请尝试重新表述您的问题以代表您的实际问题,并尽可能提供所有信息。 Parent 在你的控制范围内吗?你能重构它吗?
  • 未在第一个代码块中写入extends Parent 是一个错误,我现在已修复。我可以访问 Parent 和 Child 类,并且可以重构它们。我正在更新问题以重新解释问题。
  • Omkar 对不起,我还是不明白。首先,您的第一个块仍然无法编译,并且再次没有意义,您必须将name 传递给构造函数,使用不存在的默认值覆盖是什么意思? - 其次,“子对象定义一个“名称”属性”如果子对象定义了name它有名称,它不需要覆盖任何东西,除非你想定义一个接受父对象的函数你想通过一个孩子。
  • 第三,“可能会或可能不会覆盖trait/class的属性”,如果字段是抽象的,你必须定义,如果两者都是具体的,你必须覆盖。如果父级是具体的,而子级没有它,它将继承,您不必在子级中定义任何内容。 - 让我重新提出你的问题,看看我是否明白了,你想从参数中填充配置,如果其中一些不存在,则使用默认值。对吗?
  • 回应“第三条”评论,是的,我想填写一个配置。如果某些值不存在,则 scopt 保留案例类的默认值。我同意这一点,但问题是案例类继承了父类/特征的属性。关于“第二条”评论,我确实需要让函数接受父母并且我传递孩子的功能。但是,无论我尝试做什么,我都无法让代码编译。

标签: scala inheritance case-class scopt


【解决方案1】:

在 Scala 中,构造函数的默认值被编译为在伴随对象的上下文中计算的函数,所以

case class CaseClazz(foo: String = super.bar) extends Bar

编译成类似的东西(为了清楚起见,我没有修改名称):

class Bar { def bar: String = "whatevs" }

case class CaseClazz(foo: String = CaseClazz.defaultForFoo) extends Bar

object CaseClazz extends Function1[String, CaseClazz] {
  def defaultForFoo: String = super.bar
  def apply(foo: String = defaultForFoo): CaseClazz = new CaseClazz(foo)
}

无法编译,因为对象中的super 是CaseClazz$,它没有定义bar 方法。

获得您所寻求的行为的最清晰方法是 IMO:

object Parent {
  val defaultName: String = "Al"
}

class Parent(val name: String = Parent.defaultName) { def parentBehavior: Unit = println("parent!") }

case class Child(id: String = "55", override val name: String = Parent.defaultName) extends Parent(name)

允许:

scala> Child(id = "ego").parentBehavior
parent!

scala> Child(id = "ego").name
res12: String = Al

scala> Child().name
res13: String = Al

scala> Child().parentBehavior
parent!

【讨论】:

  • 我发现您的解决方案很有用,但由于我继承了 Parent 类,因此不得不在 Child 中再次编写 override val name: String = Parent.defaultName 并不高兴。理想的解决方案不需要在子案例类声明中再次指定name 属性,但同时在调用这些继承属性上的复制等方法时,所有父/继承属性都可用。您能否分享一下您的解决方案将如何修改?另外,我计划为父级使用特征而不是类。早些时候我不确定这个
【解决方案2】:
case class Child(id: String = "55", override val name: String = super.name) extends Parent

没用,但是

 case class Child(id: String = "55", override val name: String) extends Parent(name)

会...

您必须向Parent 提供构造函数参数才能对其进行实例化。

【讨论】:

    猜你喜欢
    • 2018-06-02
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    相关资源
    最近更新 更多