1. ホーム
  2. スカラ

[解決済み】関数を定義する "def "と "val "の違いとは?

2022-04-04 13:50:51

質問

何が違うのか。

def even: Int => Boolean = _ % 2 == 0

val even: Int => Boolean = _ % 2 == 0

のように、どちらも呼び出すことができます。 even(10) .

どのように解決するのか?

方法 def even は呼び出し時に評価され、毎回新しい関数が作成されます(新しいインスタンス Function1 ).

def even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = false

val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true

def は、呼び出すたびに新しい関数を取得することができます。

val test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -1049057402
test()
// Int = -1049057402 - same result

def test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -240885810
test()
// Int = -1002157461 - new result

val は定義されているときに評価されます。 def - を呼び出すと

scala> val even: Int => Boolean = ???
scala.NotImplementedError: an implementation is missing

scala> def even: Int => Boolean = ???
even: Int => Boolean

scala> even
scala.NotImplementedError: an implementation is missing

なお、第3の選択肢もあります。 lazy val .

最初に呼ばれたときに評価される。

scala> lazy val even: Int => Boolean = ???
even: Int => Boolean = <lazy>

scala> even
scala.NotImplementedError: an implementation is missing

しかし、同じ結果(この場合は同じインスタンスの FunctionN ) を毎回実行します。

lazy val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true

lazy val test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -1068569869
test()
// Int = -1068569869 - same result

パフォーマンス

val は定義されているときに評価されます。

def は呼び出すたびに評価されるので、パフォーマンスは val を複数回呼び出した場合。1回の呼び出しで同じパフォーマンスを得ることができます。また、呼び出しがない場合は def そのため、いくつかの分岐で使用しない場合でも、定義しておくことができます。

を使用すると lazy val へのアクセスのたびに二重ロックをかけるので、若干のオーバーヘッドが発生します。 lazy val .

SargeBorschが指摘したように、methodを定義することができ、これは最も速いオプションです。

def even(i: Int): Boolean = i % 2 == 0

しかし、関数合成のための関数(メソッドではない)が必要な場合や、高次関数(例えば filter(even) ) コンパイラはメソッドを関数として使用するたびにそのメソッドから関数を生成するので、パフォーマンスが val .