четверг, 16 мая 2013 г.

Управляющие конструкции (Control structures)

Привет!

Во многих языках программирования есть конструкции управления выполнением кода - for, while, if etc.

Где-то их больше, где-то -- меньше. Они составляют базис языка.

Scala -- не исключение и тоже содержит некоторое число встроенных управляющих конструкций (напр. if, for) но в ней возможно написать нечто свое очень похожее внешне на "control structure".

Т.е. выглядящее вот так:

  1. breakable {
  2. // your code is here
  3. if (someCondition) {
  4. break
  5. }
  6. }

С виду очень похожее на "встроенную" возможность языка, но breakable входит в scala-library.jar как простая фунция.
Тем, кому не хватало какой-нибудь экзотической конструкции могут написать ее сами.

 

Пример ниже:

  1. type Resource = BufferedReader
  2. type ResourceUsage = (Resource => Any)
  3.  
  4. def use(closable: => Resource)(code: => ResourceUsage) {
  5. /**
  6. * Function in function. Comfortable isn't it?
  7. */
  8. def handleEx(e: IOException) {
  9. sys.error(e.getStackTraceString)
  10. }
  11.  
  12. try {
  13. val resourceToClose = closable
  14.  
  15. // use opened resource
  16. code(resourceToClose)
  17.  
  18. resourceToClose.close()
  19. } catch {
  20. case e: IOException => {
  21. handleEx(e)
  22. }
  23. }
  24. }
Эта структура, названная use избавляет нас от необходимости писать try-catch при использовании файла. 
К тому же она сама закроет reader в конце работы с ним.                               
                                                        
Так называемый call-by-name приводит к тому, что выражение:

new BufferedReader(new FileReader(new File("c:\\tmp\\1.txt")))

вызывается внутри ф-и, а не до вызова use. В Java для подобного нужно было бы делать некий callback интерфейс, который нужно было бы "дёргать" из функции use() вызывая нужный блок кода "потом".

А поскольку блок val resourceToClose = closable находится в тесном окружении блока try-catch внутри функции, то и беспокоиться за "вылет" исключения при вызове use() не нужно. Все будет обработано внутри def use().

Ф-я use() "каррированная" -- возвращает ф-ю, которая использует параметр переданный в порождающию функцию use(). Это дает возможность передать второй параметр (блок кода, который работает с открытым ридером) не в скобках, а используя "{}". 
Что делает use() ничем не отличающейся с виду от того же "while() {}".

Кстати, def handleEx(e: IOException) находится внутри ф-и use(...) что очень удобно с точки зрения логической группировки кода (к подобному удобству привыкли те, кто достаточно поработал с Javascript).

Итог

Количество "своих" управляющих конструкций ограниченно разве что необходимостью в проекте и желанием автора. 

Возможность несомненно понравится тем, кто мигрирует с других языков и кто имеет набор понравившихся функций которые есть там, но которых не хватает в Scala.

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

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