В Scala, как бы вы объявили статические данные внутри функции? - PullRequest
26 голосов
/ 04 октября 2009

Во многих ситуациях я нахожу, что мне нужно создать долгоживущие значения внутри области действия функции, и нет необходимости, чтобы эти данные находились в области видимости класса / объекта.

Например,

object Example {

   def activeUsers = {
       val users = getUsersFromDB  // Connects to the database and runs a query.
       users.filter(_.active)
   }
}

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

Чтобы избежать этого, я мог бы переместить переменную users за пределы области действия функции:

object Example {
   val users = getUsersFromDB  // Connects to the database and runs a query

   def activeUsers = {
       users.filter(_.active)
   }
}

Но это делает его доступным и для других функций.

Иначе, я мог бы создать отдельный объект для включения функции:

object Example {

   object activeUsers {
       val users = getUsersFromDB  // Connects to the database and runs a query.

       def apply() = {
           users.filter(_.active)
       }
   }
}

Но это включает в себя дополнительный шаблонный код, использование другого объекта и небольшие странности синтаксиса, связанные с apply.

  • Поддерживается ли что-то подобное на уровне языка?
  • Если нет, то какой стандартный метод вы используете в этой ситуации?

Ответы [ 2 ]

35 голосов
/ 04 октября 2009

Другой вариант будет использовать замыкание:

object Example {
   val activeUsers = {
       val users = getUsersFromDB
       () => users.filter(_.active)
   }
}

Объяснение

activeUsers - это переменная типа Function1[Unit, ...your filter result type...] (или мы можем записать этот тип как (Unit => ...your filter result type...), то же самое), то есть эта переменная хранит функцию. Таким образом, вы можете использовать его позже неотличимым от функции способом, таким как activeUsers()

Мы инициализируем эту переменную блоком кода, в котором объявляем переменную users и используем ее внутри анонимной функции () => users.filter(_.active), следовательно, она является замыканием (так как имеет связанную переменную users).

В результате мы достигаем ваших целей: (1) activeUsers выглядит как метод; (2) users рассчитывается один раз; и (3) filter работает на каждый звонок.

6 голосов
/ 04 октября 2009

Расширение FunctionXX - это еще один способ достижения цели; это может иметь преимущество в предоставлении лучшей документации. Оба типа параметра и тип возвращаемого значения видны в первой строке объявления:

val activeUser = new Function0[List[String]] {
  val users = getUsersFromDB
  def apply = users filter (_.active)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...