среда, 15 мая 2013 г.

Неявные преобразования (Implicit conversions)

Привет всем!

Не один раз нам приходилось писать что-то наподобии:

  1. val button = new JButton
  2.  
  3. button.addActionListener(new ActionListener {
  4. def actionPerformed(e: ActionEvent) {
  5. println("A lot of boiler-plate code.")
  6. }
  7. })

Код выше -- не Скале, но код на Java немногим отличается (да еще и более многословен).

Все вроде нормально, но он содержит так называемый boiler plate code.
Т.е. к смысловому значению "подмешивается"  "обвязка", код, который нужен языку, а не программисту.

Смысл тут в строке println(...) и в том что мы "вешаем" обработчик на кнопку. Создание анонимного внутреннего класса (который имплементирует интерфейс ActionListener) и описание метода actionPerformed(...) это то, что приходится писать, а не то что хочется.

Использую возможность Скалы неявного преобразования типов можно свести вышеописанное к простому виду:

  1. button.addActionListener((e: ActionEvent) => {
  2. println("Much better")
  3. })

Напишите функцию в scope кода выше:

  1. /**
  2. * Implicit conversion function:
  3. * from function: (ActionEvent => Any)
  4. *
  5. * Note: You can choose any name you want for this function
  6. */
  7. implicit def ActionListenerToFunction(fn: (ActionEvent => Any)) = new ActionListener {
  8. def actionPerformed(e: ActionEvent) {
  9. fn(e)
  10. }
  11. }

Эту функцию также можно подключать во всех классах где она может быть нужной (что и делается в очень многих местах стандартной библиотеки классов Scala).

Как все это работает:

Если в коде встречается функция, которая принимает ActionEvent, а возвращает тип Any, то происходит замена такого кода кодом: 

    new ActionListener {
      def actionPerformed(e: ActionEvent) {
        fn(e)
      }
    }  
т.е.неявная функция-преобразователь сделает за нас работу по имплементированию  интерфейса и вызовет fn() с параметром "е". А сама fn(...)  это --
    (e: ActionEvent) => {
       println("Much better")
    })

Техника неявного преобразования широко используется в языке Скала и является одной из возможностей, которой нет в Java.

Главное -- это использовать ее в меру, поскольку подключения массы таких функций из разных мест может серьезно осложнить чтение кода.

Комментариев нет:

Отправить комментарий