違いは何ですか:
def even: Int => Boolean = _ % 2 == 0
そして
val even: Int => Boolean = _ % 2 == 0
どちらものように呼び出すことができますeven(10)
。
違いは何ですか:
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
と、遅延評価が得られます。一部のブランチでそれを使用しない場合でも定義でき、評価は1回またはまったく行われませんlazy val
。
@SargeBorschが指摘したように、メソッドを定義することができ、これが最速のオプションです。
def even(i: Int): Boolean = i % 2 == 0
ただし、関数の構成または高次の関数(などfilter(even)
)に関数(メソッドではない)が必要な場合、コンパイラーは関数として使用するたびにメソッドから関数を生成するため、を使用する場合よりもパフォーマンスがわずかに低下する可能性がありますval
。
even
呼び出されるたびに関数を評価することは重要ではありませんか。
def
メソッドを定義するために使用でき、これが最速のオプションです。@ A.Karimi
even eq even
。
このことを考慮:
scala> def even: (Int => Boolean) = {
println("def");
(x => x % 2 == 0)
}
even: Int => Boolean
scala> val even2: (Int => Boolean) = {
println("val");
(x => x % 2 == 0)
}
val //gets printed while declaration. line-4
even2: Int => Boolean = <function1>
scala> even(1)
def
res9: Boolean = false
scala> even2(1)
res10: Boolean = false
違いがわかりますか?要するに:
def:を呼び出すたびeven
に、even
メソッドの本体が再度呼び出されます。しかしeven2
ie valを使用すると、関数は宣言時に1回だけ初期化され(したがって、val
4行目に出力され、それ以降は表示されません)、アクセスするたびに同じ出力が使用されます。たとえば、これを試してください:
scala> import scala.util.Random
import scala.util.Random
scala> val x = { Random.nextInt }
x: Int = -1307706866
scala> x
res0: Int = -1307706866
scala> x
res1: Int = -1307706866
ときにx
初期化され、値が返されたことにより、Random.nextInt
最終的な値として設定されていますx
。次回x
は再度使用すると、常に同じ値が返されます。
遅延初期化することもできますx
。つまり、最初に使用されるときは、宣言時ではなく初期化されます。例えば:
scala> lazy val y = { Random.nextInt }
y: Int = <lazy>
scala> y
res4: Int = 323930673
scala> y
res5: Int = 323930673
even2
回ずつ、2回呼び出してみます。通話ごとに異なる回答が得られます。したがって、後続の呼び出しではは実行されませんが、への異なる呼び出しから同じ結果が得られることはありません。が再度実行されない理由については、別の質問です。1
2
println
even2
println
valつまり「sq」はScalaの定義によるもので、修正されています。宣言時に正しく評価され、後で変更することはできません。その他の例では、even2もvalですが、関数シグネチャ、つまり "(Int => Boolean)"で宣言されているため、Int型ではありません。それは関数であり、その値は次の式によって設定されます
{
println("val");
(x => x % 2 == 0)
}
Scalaのvalプロパティに従って、sqと同じ規則で、even2に別の関数を割り当てることはできません。
eval2 val関数を呼び出すと「val」が何度も出力されないのはなぜですか?
元のコード:
val even2: (Int => Boolean) = {
println("val");
(x => x % 2 == 0)
}
Scalaでは、上記の式({..}内)の最後のステートメントは実際には左側に戻ります。つまり、even2を "x => x%2 == 0"関数に設定することになります。これは、even2 val型に対して宣言した型(Int => Boolean)と一致するため、コンパイラーは幸せです。Even2は "(x => x%2 == 0)"関数(つまり、println( "val")などの前の他のステートメントではない)のみを指すようになりました。異なるパラメーターでevent2を呼び出すと、実際には "(x => x%2 == 0) "コード、それだけがevent2で保存されるため。
scala> even2(2)
res7: Boolean = true
scala> even2(3)
res8: Boolean = false
これをより明確にするために、以下はコードの異なるバージョンです。
scala> val even2: (Int => Boolean) = {
| println("val");
| (x => {
| println("inside final fn")
| x % 2 == 0
| })
| }
何が起こるか ?ここで、even2()を呼び出すと、「inside final fn」が何度も何度も出力されます。
scala> even2(3)
inside final fn
res9: Boolean = false
scala> even2(2)
inside final fn
res10: Boolean = true
scala>
上記の役立つ回答に加えて、私の発見は次のとおりです。
def test1: Int => Int = {
x => x
}
--test1: test1[] => Int => Int
def test2(): Int => Int = {
x => x+1
}
--test2: test2[]() => Int => Int
def test3(): Int = 4
--test3: test3[]() => Int
上記は、「def」が呼び出されたときに別の関数「Int => Int」を返す(引数パラメーターがゼロの)メソッドであることを示しています。
メソッドから関数への変換については、https://tpolecat.github.io/2014/06/09/methods-functions.htmlで詳しく説明しています。
REPLでは、
scala> def even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean
scala> val even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean = $$Lambda$1157/1017502292@57a0aeb8
defとは call-by-name
、オンデマンドで評価される
valはcall-by-value
、初期化中に評価されます
Int => Boolean
意味ですか?私は、define構文はdef foo(bar: Baz): Bin = expr