case-класс, наследующий другой класс / признак

Я хочу, чтобы кейс-класс расширил черту

Вот мои требования:

  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() на объекте класса дела. В качестве обходного пути я могу изменить значение name приписывать через childObj.name = "newName"
  4. Я должен (жесткое требование) иметь возможность переопределить значения атрибутов, которые дочерний объект унаследовал от родительского. Прямо сейчас это возможно, потому что я объявил родительские атрибуты как var вместо вал. Однако в идеале я хотел бы сделать его неизменным и использовать метод copy для изменения значений.

Это то, что у меня есть сейчас, но я не могу использовать .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". Например, рассмотрим функцию, которая добавит "Mr." или "миссис" данный объект Child имеет атрибут name.

Общая предыстория происходящего: я заполняю конфиг входными значениями командной строки (в класс case), используя scopt. Если значение не указано, для этого атрибута используется значение по умолчанию. Под атрибутом я подразумеваю член данных внутри класса case. У меня есть функция (назовем ее dbReader), которая принимает объект класса case и использует его для установления соединения и чтения из базы данных. В моем проекте много разных классов параметров, и я хочу, чтобы каждый из этих параметров реализовывал общие DatabaseConnectionParameters Эта черта позволяет функции dbReader работать независимо от того, какой класс регистра параметров передается ей.

2 ответа

В 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!
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 чтобы иметь возможность создать его экземпляр.

Другие вопросы по тегам