case-класс, наследующий другой класс / признак - PullRequest
2 голосов
/ 28 мая 2019

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

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

  1. Мне нужно использовать класс дел для ребенка.Это сложное требование из-за scopt (https://github.com/scopt/scopt)
  2. Родитель должен быть чертой. Извинения за то, что раньше я не знал об этом
  3. Я хочу, чтобы атрибуты родительской черты былидоступны для дочернего элемента и, предпочтительно, не должны указывать их снова при объявлении дочернего класса case. Например, если родительская черта: 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. Я должен (жесткое требование) иметь возможность переопределять значения атрибутов, которые дочерний объект унаследовал от родителя. Сейчас это возможно, потому что вместо этого я объявил родительские атрибуты как varval. Однако, в идеале я хотел бы сделать его неизменным и использовать вместо него метод копирования для изменения значений.

Thisэто то, что у меня есть сейчас, но я не могу использовать метод .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 ]

6 голосов
/ 28 мая 2019

В 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.

Самый ясный способ получить поведение, которое вы ищете, - это ИМО:

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!
0 голосов
/ 28 мая 2019
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, чтобы иметь возможность его создания.

...