Call-by-Name: => Ketik
The => Type
notasi singkatan call-by-nama, yang merupakan salah satu dari banyak cara parameter dapat dilewatkan. Jika Anda tidak terbiasa dengan mereka, saya sarankan meluangkan waktu untuk membaca artikel wikipedia itu, meskipun saat ini sebagian besar panggilan-oleh-nilai dan panggilan-oleh-referensi.
Apa artinya adalah bahwa apa yang dilewatkan diganti dengan nama nilai di dalam fungsi. Misalnya, ambil fungsi ini:
def f(x: => Int) = x * x
Jika saya menyebutnya seperti ini
var y = 0
f { y += 1; y }
Maka kode akan dieksekusi seperti ini
{ y += 1; y } * { y += 1; y }
Meskipun itu memunculkan poin tentang apa yang terjadi jika ada bentrokan nama pengidentifikasi. Dalam panggilan-dengan-nama tradisional, suatu mekanisme yang disebut subtitusi penghindaran terjadi untuk menghindari perselisihan nama. Di Scala, bagaimanapun, ini diimplementasikan dengan cara lain dengan hasil yang sama - nama pengidentifikasi di dalam parameter tidak dapat merujuk atau pengidentifikasi bayangan dalam fungsi yang dipanggil.
Ada beberapa hal lain yang terkait dengan panggilan-nama-yang akan saya bicarakan setelah menjelaskan dua lainnya.
0-arity Fungsi: () => Ketik
Sintaksnya () => Type
adalah tipe a Function0
. Yaitu, fungsi yang tidak mengambil parameter dan mengembalikan sesuatu. Ini sama dengan, katakanlah, memanggil metode size()
- tidak memerlukan parameter dan mengembalikan nomor.
Sangat menarik, bagaimanapun, bahwa sintaks ini sangat mirip dengan sintaks untuk fungsi literal anonim , yang merupakan penyebab kebingungan. Sebagai contoh,
() => println("I'm an anonymous function")
adalah fungsi anonim literal dari arity 0, yang tipenya adalah
() => Unit
Jadi kita bisa menulis:
val f: () => Unit = () => println("I'm an anonymous function")
Namun, penting untuk tidak membingungkan tipe dengan nilainya.
Unit => Jenis
Ini sebenarnya hanya sebuah Function1
, yang parameter pertamanya bertipe Unit
. Cara lain untuk menulisnya adalah (Unit) => Type
atau Function1[Unit, Type]
. Masalahnya adalah ... ini tidak mungkin menjadi apa yang diinginkan seseorang. The Unit
Tujuan utama tipe ini mengindikasikan nilai salah satu tidak tertarik, jadi tidak masuk akal untuk menerima nilai tersebut.
Pertimbangkan, misalnya,
def f(x: Unit) = ...
Apa yang bisa dilakukan seseorang x
? Ini hanya dapat memiliki nilai tunggal, jadi orang tidak perlu menerimanya. Satu kemungkinan penggunaan adalah fungsi chaining kembali Unit
:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
Karena andThen
hanya didefinisikan Function1
, dan fungsi-fungsi yang kita gunakan kembali Unit
, kita harus mendefinisikannya sebagai tipe Function1[Unit, Unit]
untuk dapat mengaitkannya.
Sumber Kebingungan
Sumber pertama kebingungan adalah memikirkan kesamaan antara tipe dan literal yang ada untuk fungsi 0-arity juga ada untuk panggilan-dengan-nama. Dengan kata lain, memikirkan itu, karena
() => { println("Hi!") }
adalah untuk harfiah () => Unit
, maka
{ println("Hi!") }
akan menjadi literal untuk => Unit
. Bukan itu. Itu adalah blok kode , bukan literal.
Sumber kebingungan lainnya adalah bahwa nilaiUnit
type ditulis , yang terlihat seperti daftar parameter 0-arity (tetapi tidak).()
case class Scheduled(time: Int)(callback: => Unit)
. Ini berfungsi karena daftar parameter sekunder tidak diekspos secara publik, juga tidak termasuk dalam metodeequals
/ yang dihasilkanhashCode
.