Hai, apa Int => Booleanartinya? Saya pikir sintaks define adalahdef foo(bar: Baz): Bin = expr
Ziu
@Ziu yang berarti fungsi 'even' menerima Int sebagai argumen dan mengembalikan Boolean sebagai tipe nilai. Jadi, Anda dapat memanggil 'genap (3)' yang dievaluasi menjadi Boolean 'salah'
Denys Lobur
@DenysLobur terima kasih atas balasan Anda! Adakah referensi tentang sintaks ini?
Ziu
@Ziu Saya pada dasarnya menemukannya dari kursus Coursera Odersky - coursera.org/learn/progfun1 . Pada saat Anda menyelesaikannya, Anda akan mengerti apa arti 'Type => Type'
Denys Lobur
Jawaban:
325
Metode def evenmengevaluasi panggilan dan membuat fungsi baru setiap waktu (instance baru Function1).
def even:Int=>Boolean= _ %2==0
even eq even
//Boolean = falseval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = true
Dengan defAnda bisa mendapatkan fungsi baru di setiap panggilan:
val test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -1049057402
test()// Int = -1049057402 - same resultdef test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -240885810
test()// Int = -1002157461 - new result
valmengevaluasi ketika didefinisikan, def- ketika dipanggil:
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
Perhatikan bahwa ada pilihan ketiga: lazy val.
Ini mengevaluasi ketika dipanggil pertama kali:
scala>lazyval even:Int=>Boolean=???
even:Int=>Boolean=<lazy>
scala> even
scala.NotImplementedError: an implementation is missing
Tetapi mengembalikan hasil yang sama (dalam hal ini contoh yang sama FunctionN) setiap kali:
lazyval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = truelazyval test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -1068569869
test()// Int = -1068569869 - same result
Performa
val mengevaluasi ketika didefinisikan.
defmengevaluasi setiap panggilan, sehingga kinerjanya bisa lebih buruk daripada valuntuk beberapa panggilan. Anda akan mendapatkan kinerja yang sama dengan satu panggilan. Dan tanpa panggilan, Anda tidak akan mendapatkan overhead def, sehingga Anda dapat menentukannya meskipun Anda tidak akan menggunakannya di beberapa cabang.
Dengan lazy valAnda akan mendapatkan evaluasi malas: Anda dapat mendefinisikannya bahkan jika Anda tidak akan menggunakannya di beberapa cabang, dan itu mengevaluasi sekali atau tidak pernah, tetapi Anda akan mendapatkan sedikit overhead dari penguncian cek ganda pada setiap akses ke Anda lazy val.
Seperti @SargeBorsch catat, Anda dapat mendefinisikan metode, dan ini adalah opsi tercepat:
def even(i:Int):Boolean= i %2==0
Tetapi jika Anda memerlukan fungsi (bukan metode) untuk komposisi fungsi atau untuk fungsi urutan yang lebih tinggi (seperti filter(even)) kompiler akan menghasilkan fungsi dari metode Anda setiap kali Anda menggunakannya sebagai fungsi, sehingga kinerja bisa sedikit lebih buruk daripada dengan val.
Bisakah Anda membandingkannya mengenai kinerja? Bukankah penting untuk mengevaluasi fungsi setiap kali evendipanggil.
Amir Karimi
2
defdapat digunakan untuk mendefinisikan metode, dan ini adalah opsi tercepat. @ A.Karimi
Nama Tampilan
2
Untuk bersenang-senang: pada 2.12 even eq even,.
som-snytt
Apakah ada konsep fungsi inline seperti di c ++? Saya berasal dari dunia c ++, jadi maafkan ketidaktahuan saya.
animageofmine
2
@animageofmine Scala compiler dapat mencoba metode inline. Ada @inlineatribut untuk ini. Tapi itu tidak bisa inline fungsi karena pemanggilan fungsi adalah panggilan ke applymetode virtual objek fungsi. JVM mungkin melakukan devirtualise dan inline panggilan semacam itu dalam beberapa situasi, tetapi tidak secara umum.
senia
24
Pertimbangkan ini:
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
Apakah Anda melihat perbedaannya? Pendeknya:
def : Untuk setiap panggilan even, ia memanggil tubuh evenmetode lagi. Tetapi dengan valeven2 yaitu , fungsi diinisialisasi hanya sekali saat deklarasi (dan karenanya ia mencetak pada baris 4 dan tidak pernah lagi) dan output yang sama digunakan setiap kali diakses. Misalnya coba lakukan ini:val
scala>import scala.util.Randomimport scala.util.Random
scala>val x ={Random.nextInt }
x:Int=-1307706866
scala> x
res0:Int=-1307706866
scala> x
res1:Int=-1307706866
Ketika xdiinisialisasi, nilai yang dikembalikan oleh Random.nextIntditetapkan sebagai nilai akhir dari x. Lain kali xdigunakan lagi, itu akan selalu mengembalikan nilai yang sama.
Anda juga dapat dengan malas menginisialisasi x. yaitu pertama kali digunakan itu diinisialisasi dan bukan saat deklarasi. Sebagai contoh:
scala>lazyval y ={Random.nextInt }
y:Int=<lazy>
scala> y
res4:Int=323930673
scala> y
res5:Int=323930673
Saya pikir penjelasan Anda mungkin menyiratkan sesuatu yang tidak Anda maksudkan. Coba panggil even2dua kali, sekali dengan 1dan sekali dengan 2. Anda akan mendapatkan jawaban berbeda di setiap panggilan. Jadi, sementara printlntidak dieksekusi di panggilan berikutnya, Anda tidak mendapatkan hasil yang sama dari panggilan yang berbeda even2. Mengapa printlntidak dieksekusi lagi, itu pertanyaan yang berbeda.
Melston
1
itu sebenarnya sangat menarik. Seperti dalam kasus val yaitu even2, val dievaluasi ke nilai parameter. jadi ya dengan val Anda evaluasi fungsi, nilainya. Println bukan bagian dari nilai yang dievaluasi. Ini adalah bagian dari evaluasi tetapi bukan nilai yang dievaluasi. Kuncinya di sini adalah bahwa nilai yang dievaluasi sebenarnya adalah nilai parametarized, yang bergantung pada beberapa input. hal yang cerdas
MaatDeamon
1
@melston tepatnya! itulah yang saya mengerti, jadi mengapa println tidak bisa dieksekusi lagi ketika output berubah?
aur
1
@aur apa yang dikembalikan oleh even2 sebenarnya adalah sebuah fungsi (ekspresi di dalam tanda kurung di akhir definisi even2). Fungsi itu sebenarnya dipanggil dengan parameter yang Anda berikan ke even2 setiap kali Anda memohonnya.
melston
5
Lihat ini:
var x =2// using var as I need to change it to 3 laterval sq = x*x // evaluates right now
x =3// no effect! sq is already evaluated
println(sq)
Anehnya, ini akan mencetak 4 dan bukan 9! val (even var) dievaluasi segera dan ditugaskan.
Sekarang ganti val ke def .. ini akan mencetak 9! Def adalah panggilan fungsi .. itu akan mengevaluasi setiap kali dipanggil.
val yaitu "sq" adalah dengan definisi Scala diperbaiki. Itu dievaluasi tepat pada saat deklarasi, Anda tidak dapat mengubahnya nanti. Dalam contoh lain, di mana even2 juga val, tetapi dinyatakan dengan tanda tangan fungsi yaitu "(Int => Boolean)", jadi itu bukan tipe Int. Ini adalah fungsi dan nilainya diatur dengan mengikuti ekspresi
{
println("val");(x => x %2==0)}
Sesuai properti Scala val, Anda tidak dapat menetapkan fungsi lain ke even2, aturan yang sama dengan sq.
Tentang mengapa memanggil fungsi val eval2 tidak mencetak "val" lagi dan lagi?
Kode asal:
val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}
Kita tahu, dalam Scala pernyataan terakhir tentang jenis ekspresi di atas (di dalam {..}) sebenarnya kembali ke sisi kiri. Jadi Anda akhirnya menetapkan even2 ke fungsi "x => x% 2 == 0", yang cocok dengan tipe yang Anda nyatakan untuk tipe val even2 yaitu (Int => Boolean), jadi kompiler senang. Sekarang even2 hanya menunjuk ke fungsi "(x => x% 2 == 0)" (bukan pernyataan lain sebelumnya yaitu println ("val") dll. Memanggil event2 dengan parameter yang berbeda akan benar-benar memanggil "(x => x% 2 == 0) "kode, karena hanya kode yang disimpan dengan event2.
Mengeksekusi definisi seperti def x = etidak akan mengevaluasi ekspresi e. Sebagai gantinya e dievaluasi setiap kali x dipanggil.
Sebagai alternatif, Scala menawarkan definisi nilai
val x = e, yang mengevaluasi sisi kanan sebagai bagian dari evaluasi definisi. Jika x kemudian digunakan kemudian, itu segera diganti dengan nilai pra-dihitung dari e, sehingga ekspresi tidak perlu dievaluasi lagi.
juga, Val adalah evaluasi nilai. Yang berarti ekspresi sisi kanan dievaluasi selama definisi. Di mana Def adalah dengan evaluasi nama. Itu tidak akan mengevaluasi sampai digunakan.
Selain balasan yang bermanfaat di atas, temuan saya adalah:
def test1:Int=>Int={
x => x
}--test1: test1[]=>Int=>Intdef test2():Int=>Int={
x => x+1}--test2: test2[]()=>Int=>Intdef test3():Int=4--test3: test3[]()=>Int
Di atas menunjukkan bahwa "def" adalah metode (dengan parameter argumen nol) yang mengembalikan fungsi lain "Int => Int" ketika dipanggil.
Dengan pertanyaan yang sudah tua ini, dan dengan begitu banyak jawaban yang sudah dikirimkan, sering kali membantu menjelaskan bagaimana jawaban Anda berbeda dari, atau menambah, informasi yang disediakan dalam jawaban yang ada.
Int => Boolean
artinya? Saya pikir sintaks define adalahdef foo(bar: Baz): Bin = expr
Jawaban:
Metode
def even
mengevaluasi panggilan dan membuat fungsi baru setiap waktu (instance baruFunction1
).Dengan
def
Anda bisa mendapatkan fungsi baru di setiap panggilan:val
mengevaluasi ketika didefinisikan,def
- ketika dipanggil:Perhatikan bahwa ada pilihan ketiga:
lazy val
.Ini mengevaluasi ketika dipanggil pertama kali:
Tetapi mengembalikan hasil yang sama (dalam hal ini contoh yang sama
FunctionN
) setiap kali:Performa
val
mengevaluasi ketika didefinisikan.def
mengevaluasi setiap panggilan, sehingga kinerjanya bisa lebih buruk daripadaval
untuk beberapa panggilan. Anda akan mendapatkan kinerja yang sama dengan satu panggilan. Dan tanpa panggilan, Anda tidak akan mendapatkan overheaddef
, sehingga Anda dapat menentukannya meskipun Anda tidak akan menggunakannya di beberapa cabang.Dengan
lazy val
Anda akan mendapatkan evaluasi malas: Anda dapat mendefinisikannya bahkan jika Anda tidak akan menggunakannya di beberapa cabang, dan itu mengevaluasi sekali atau tidak pernah, tetapi Anda akan mendapatkan sedikit overhead dari penguncian cek ganda pada setiap akses ke Andalazy val
.Seperti @SargeBorsch catat, Anda dapat mendefinisikan metode, dan ini adalah opsi tercepat:
Tetapi jika Anda memerlukan fungsi (bukan metode) untuk komposisi fungsi atau untuk fungsi urutan yang lebih tinggi (seperti
filter(even)
) kompiler akan menghasilkan fungsi dari metode Anda setiap kali Anda menggunakannya sebagai fungsi, sehingga kinerja bisa sedikit lebih buruk daripada denganval
.sumber
even
dipanggil.def
dapat digunakan untuk mendefinisikan metode, dan ini adalah opsi tercepat. @ A.Karimieven eq even
,.@inline
atribut untuk ini. Tapi itu tidak bisa inline fungsi karena pemanggilan fungsi adalah panggilan keapply
metode virtual objek fungsi. JVM mungkin melakukan devirtualise dan inline panggilan semacam itu dalam beberapa situasi, tetapi tidak secara umum.Pertimbangkan ini:
Apakah Anda melihat perbedaannya? Pendeknya:
def : Untuk setiap panggilan
even
, ia memanggil tubuheven
metode lagi. Tetapi dengan valeven2
yaitu , fungsi diinisialisasi hanya sekali saat deklarasi (dan karenanya ia mencetak pada baris 4 dan tidak pernah lagi) dan output yang sama digunakan setiap kali diakses. Misalnya coba lakukan ini:val
Ketika
x
diinisialisasi, nilai yang dikembalikan olehRandom.nextInt
ditetapkan sebagai nilai akhir darix
. Lain kalix
digunakan lagi, itu akan selalu mengembalikan nilai yang sama.Anda juga dapat dengan malas menginisialisasi
x
. yaitu pertama kali digunakan itu diinisialisasi dan bukan saat deklarasi. Sebagai contoh:sumber
even2
dua kali, sekali dengan1
dan sekali dengan2
. Anda akan mendapatkan jawaban berbeda di setiap panggilan. Jadi, sementaraprintln
tidak dieksekusi di panggilan berikutnya, Anda tidak mendapatkan hasil yang sama dari panggilan yang berbedaeven2
. Mengapaprintln
tidak dieksekusi lagi, itu pertanyaan yang berbeda.Lihat ini:
Anehnya, ini akan mencetak 4 dan bukan 9! val (even var) dievaluasi segera dan ditugaskan.
Sekarang ganti val ke def .. ini akan mencetak 9! Def adalah panggilan fungsi .. itu akan mengevaluasi setiap kali dipanggil.
sumber
val yaitu "sq" adalah dengan definisi Scala diperbaiki. Itu dievaluasi tepat pada saat deklarasi, Anda tidak dapat mengubahnya nanti. Dalam contoh lain, di mana even2 juga val, tetapi dinyatakan dengan tanda tangan fungsi yaitu "(Int => Boolean)", jadi itu bukan tipe Int. Ini adalah fungsi dan nilainya diatur dengan mengikuti ekspresi
Sesuai properti Scala val, Anda tidak dapat menetapkan fungsi lain ke even2, aturan yang sama dengan sq.
Tentang mengapa memanggil fungsi val eval2 tidak mencetak "val" lagi dan lagi?
Kode asal:
Kita tahu, dalam Scala pernyataan terakhir tentang jenis ekspresi di atas (di dalam {..}) sebenarnya kembali ke sisi kiri. Jadi Anda akhirnya menetapkan even2 ke fungsi "x => x% 2 == 0", yang cocok dengan tipe yang Anda nyatakan untuk tipe val even2 yaitu (Int => Boolean), jadi kompiler senang. Sekarang even2 hanya menunjuk ke fungsi "(x => x% 2 == 0)" (bukan pernyataan lain sebelumnya yaitu println ("val") dll. Memanggil event2 dengan parameter yang berbeda akan benar-benar memanggil "(x => x% 2 == 0) "kode, karena hanya kode yang disimpan dengan event2.
Hanya untuk memperjelas ini, berikut adalah versi kode yang berbeda.
Apa yang akan terjadi ? di sini kita melihat "inside final fn" dicetak berulang kali, ketika Anda memanggil even2 ().
sumber
Mengeksekusi definisi seperti
def x = e
tidak akan mengevaluasi ekspresi e. Sebagai gantinya e dievaluasi setiap kali x dipanggil.Sebagai alternatif, Scala menawarkan definisi nilai
val x = e
, yang mengevaluasi sisi kanan sebagai bagian dari evaluasi definisi. Jika x kemudian digunakan kemudian, itu segera diganti dengan nilai pra-dihitung dari e, sehingga ekspresi tidak perlu dievaluasi lagi.sumber
juga, Val adalah evaluasi nilai. Yang berarti ekspresi sisi kanan dievaluasi selama definisi. Di mana Def adalah dengan evaluasi nama. Itu tidak akan mengevaluasi sampai digunakan.
sumber
Selain balasan yang bermanfaat di atas, temuan saya adalah:
Di atas menunjukkan bahwa "def" adalah metode (dengan parameter argumen nol) yang mengembalikan fungsi lain "Int => Int" ketika dipanggil.
Konversi metode menjadi fungsi dijelaskan dengan baik di sini: https://tpolecat.github.io/2014/06/09/methods-functions.html
sumber
Dalam REPL,
def berarti
call-by-name
, dievaluasi berdasarkan permintaanval berarti
call-by-value
, dievaluasi saat inisialisasisumber