В Scala, как бы вы объявили статические данные внутри функции?
Во многих ситуациях я обнаруживаю, что мне нужно создавать долгоживущие значения внутри области функций, и нет необходимости в том, чтобы эти данные находились в области класса/объекта.
Например,
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
.
- Поддерживается ли что-то подобное на уровне языка?
- Если нет, есть ли какой-либо стандартный метод, который вы используете в этой ситуации?
Ответы
Ответ 1
Другим вариантом будет использование закрытия:
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
работает при каждом вызове.
Ответ 2
Расширение FunctionXX - еще один способ достижения цели; он может иметь преимущество в обеспечении лучшей документации. Оба типа параметров и тип возвращаемого значения видны в первой строке объявления:
val activeUser = new Function0[List[String]] {
val users = getUsersFromDB
def apply = users filter (_.active)
}