多くの場合、関数のスコープ内で長期間有効な値を作成する必要があり、このデータがクラス/オブジェクト スコープにある必要はないことがわかります。
例えば、
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
すべての呼び出しで機能するという目標が達成されます。