Расширить трейт с помощью частного параметра конструктора

Как в Scala расширить трейт в классе с помощью параметра конструктора private, который определен в трейте?

trait Parent {
  protected def name: String
  require(name != "", "wooo problem!")
}

class Child(private val name: String) extends Parent {
  println("name is " + name)
}

Вышеупомянутый класс дает ошибку:

Класс Child должен быть абстрактным, поскольку имя метода в трейте Parent типа ⇒ String не определено.

Конечно, я могу:

  1. сделать Child класс абстрактным,
  2. определить его, не используя частное в конструкторе, например class Child(val name: String).
  3. сделать Родителя abstract class вместо черты

Но с помощью вышеупомянутой реализации я не могу иметь параметр конструктора private при расширении признака? Обратите внимание, что я хочу, чтобы переменная была закрытой, чтобы я не мог делать childInstance.name.


person rgamber    schedule 27.01.2017    source источник
comment
Чего вы этим пытаетесь достичь? Зачем нужен конструктор с частной переменной? Разве вы не можете просто определить частную переменную в классе и иметь пустой конструктор?   -  person nmat    schedule 27.01.2017
comment
Поскольку этот класс расширяется несколькими дочерними элементами, я не хочу повторять код. Я думаю, что нашел способ. Если я сделаю переменную в трейте protected и изменю дочерний конструктор на Child(name: String), я не смогу получить доступ к переменной снаружи. Для меня этого достаточно!   -  person rgamber    schedule 27.01.2017
comment
Почему бы вам просто не определить class Child{ private val name = "" }?   -  person nmat    schedule 27.01.2017
comment
Это потому, что у меня есть сигнатуры методов в трейте, которые я хочу, чтобы все потомки определяли. Так что, на мой взгляд, черта имеет больше смысла! Сообщите мне, если я ошибаюсь. Извините, что я упомянул об этом в вопросе.   -  person rgamber    schedule 27.01.2017


Ответы (2)


Попробуй это

  trait Parent {
    protected def name: String
    require(name != "", "wooo problem!")
  }

  class Child(override protected val name: String) extends Parent {
    val publicVar = "Hello World"
    println("name is " + name)
  }

  def main(args: Array[String]): Unit = {
    val child = new Child("John Doe")
    println(child.publicVar)
    println(child.name) // Does not compile
  }

Вы не сможете получить доступ к child.name

person Sami Badawi    schedule 27.01.2017
comment
Как я уже упоминал в вопросе, мне нужно, чтобы переменная была частной. Так что нет, я не хочу использовать override. - person rgamber; 27.01.2017
comment
Меняю оба на защиту. Когда я изменил ребенка на частный, он больше не работает. Сообщение об ошибке: класс Child должен быть абстрактным, поскольку имя метода в свойстве Parent of type = ›String не определено - person Sami Badawi; 27.01.2017
comment
Я снова обновил код. Я думаю, что пример делает то, что вы хотите: println (child.name) // Не компилируется - person Sami Badawi; 27.01.2017
comment
Спасибо за помощь! Я нашел способ, как я уже упоминал в своем комментарии под вопросом. Подобно тому, что вы делаете, за исключением того, что мне не нужно использовать override protected val в дочернем конструкторе. - person rgamber; 27.01.2017

Если у вас есть абстрактный метод в трейте, тогда все производные классы должны иметь один и тот же (или более разрешающий) модификатор (в вашем случае, по крайней мере, защищенный) для абстрактных методов.

trait Parent {
  protected def name: String
  require(name != "", "wooo problem!")
}

class Child(private val privateName: String) extends Parent {
  override protected def name: String = privateName
  println("name is " + name)
}

Вы можете оставить свой конструктор частным, но вам нужно определить override protected def name: String и использовать частное значение вашего конструктора.

person marios    schedule 27.01.2017