Scala: хранить переменную вызова по имени как поле класса

В своем прогрессе в изучении Scala я пытаюсь реализовать простой DSL с обратными вызовами.

object Button {...} // apply 
class Button(val name: String) {
    private val: => Unit; // doesn't work

    def click(f: => Unit) = {
        _click_cb = f
        this
    }

    def onClick() = this._click_cb()
}

Button("Click me!") click {println("Clicked!")}

Я создаю новый объект, передаю ему обратный вызов для сохранения. Моя демонстрационная структура запускает метод onClick, который должен вызывать сохраненный

Это работает с () => Unit, но мой DSL выглядит некрасиво:

Button("Click me!") click (() => println("Clicked!"))

Конечно, я мог бы сделать onClick абстракцию и позже реализовать анонимный класс.

new Button("Click me!") {def onClick = println("Clicked!")}

Но я хочу поиграть с DSL и т.п.

Вопросы:

  • Как сохранить f в _click_cb?
  • Как предоставить начальную «пустую» функцию для _click_cb?
  • И, может быть, есть более scala-способ добиться этого? (без анонимных классов)

person dmzkrsk    schedule 14.05.2015    source источник
comment
Я предполагаю, что private val: => Unit на самом деле должно быть private val _click_cb: => Unit (_click_cb отсутствует). Но даже так, это не может быть валом, верно? Вы устанавливаете его в click(), поэтому он должен быть var.   -  person AmigoNico    schedule 14.05.2015
comment
Кроме того, имена click и onClick кажутся обратными: onClick должен быть тем, который вы используете, чтобы сказать, что должно произойти, когда происходит щелчок, а click должен быть тем, который вы используете, когда происходит щелчок, не так ли?   -  person AmigoNico    schedule 14.05.2015


Ответы (1)


Более уродливая версия просто для того, чтобы показать, что lazy val может хранить значение параметра по имени без его оценки:

case class Button(val name: String) {
  def clickCallback(): Unit = ()

  def click(f: => Unit) = {
    lazy val notEvaluated = f
    new Button(name) { override def clickCallback() = notEvaluated }
  }

  def onClick(): Unit = clickCallback()
}

Более чистая и функциональная реализация:

class Button(val name: String) {
  def click(f: => Unit) = new Button(name) { override def onClick() = f }

  def onClick(): Unit = ()
}
person yǝsʞǝla    schedule 14.05.2015