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