Saya membaca Fungsi Scala (bagian dari tur Scala lainnya ). Dalam pos itu ia menyatakan:
Metode dan fungsi bukan hal yang sama
Tetapi dia tidak menjelaskan apa-apa tentang itu. Apa yang dia katakan?
Saya membaca Fungsi Scala (bagian dari tur Scala lainnya ). Dalam pos itu ia menyatakan:
Metode dan fungsi bukan hal yang sama
Tetapi dia tidak menjelaskan apa-apa tentang itu. Apa yang dia katakan?
Jawaban:
Jim telah membahas hal ini cukup banyak di posting blognya , tapi saya memposting briefing di sini untuk referensi.
Pertama, mari kita lihat apa yang dikatakan Spesifikasi Scala. Bab 3 (tipe) memberi tahu kita tentang Tipe Fungsi (3.2.9) dan Tipe Metode (3.3.1). Bab 4 (deklarasi dasar) berbicara tentang Deklarasi Nilai dan Definisi (4.1), Deklarasi dan Definisi Variabel (4.2) dan Deklarasi dan Definisi Fungsi (4.6). Bab 6 (ekspresi) berbicara tentang Fungsi Anonim (6.23) dan Nilai Metode (6.7). Anehnya, nilai-nilai fungsi dibicarakan satu kali pada 3.2.9, dan tidak ada tempat lain.
Sebuah Fungsi Type adalah (kira-kira) jenis bentuk (T1, ..., Tn) => U , yang merupakan singkatan untuk sifat FunctionN
di perpustakaan standar. Fungsi dan Metode Anonim Nilai memiliki tipe fungsi, dan tipe fungsi dapat digunakan sebagai bagian dari nilai, deklarasi dan definisi variabel dan fungsi. Bahkan, itu bisa menjadi bagian dari tipe metode.
Sebuah Metode Type adalah jenis non-nilai . Itu berarti tidak ada nilai - tidak ada objek, tidak ada contoh - dengan tipe metode. Seperti disebutkan di atas, Nilai Metode sebenarnya memiliki Tipe Fungsi . Tipe metode adalah def
deklarasi - segala sesuatu tentang def
kecuali tubuhnya.
Nilai Deklarasi dan Definisi dan Deklarasi Variabel dan Definisi yang val
dan var
deklarasi, termasuk kedua jenis dan nilai - yang dapat, masing-masing, Fungsi Jenis dan Fungsi Anonymous atau Nilai Metode . Perhatikan bahwa, pada JVM, ini (nilai metode) diimplementasikan dengan apa yang disebut Java "metode".
Sebuah Fungsi Deklarasi adalah def
deklarasi, termasuk jenis dan tubuh . Bagian tipe adalah Tipe Metode, dan tubuh adalah ekspresi atau blok . Ini juga diimplementasikan pada JVM dengan apa yang disebut Java "metode".
Akhirnya, Fungsi Anonim adalah turunan dari Tipe Fungsi (yaitu, turunan dari sifat tersebut FunctionN
), dan Nilai Metode adalah hal yang sama! Perbedaannya adalah bahwa Nilai Metode dibuat dari metode, baik dengan postfixing garis bawah ( m _
adalah nilai metode yang sesuai dengan "deklarasi fungsi" ( def
) m
), atau dengan proses yang disebut ekspansi eta , yang seperti pemeran otomatis dari metode berfungsi.
Itulah yang dikatakan oleh spesifikasi, jadi izinkan saya menjelaskannya : kita tidak menggunakan terminologi itu! Ini menyebabkan terlalu banyak kebingungan antara apa yang disebut "deklarasi fungsi" , yang merupakan bagian dari program (bab 4 - deklarasi dasar) dan "fungsi anonim" , yang merupakan ekspresi, dan "tipe fungsi" , yaitu, baik tipe - sifat.
Terminologi di bawah ini, dan digunakan oleh programmer Scala yang berpengalaman, membuat satu perubahan dari terminologi spesifikasi: alih-alih mengatakan deklarasi fungsi , kami mengatakan metode . Atau bahkan deklarasi metode. Lebih lanjut, kami mencatat bahwa deklarasi nilai dan deklarasi variabel juga merupakan metode untuk tujuan praktis.
Jadi, mengingat perubahan terminologi di atas, inilah penjelasan praktis tentang perbedaan tersebut.
Sebuah fungsi adalah obyek yang termasuk salah satu FunctionX
ciri-ciri, seperti Function0
, Function1
, Function2
, dll mungkin termasuk PartialFunction
juga, yang benar-benar meluas Function1
.
Mari kita lihat jenis tanda tangan untuk salah satu ciri berikut:
trait Function2[-T1, -T2, +R] extends AnyRef
Ciri ini memiliki satu metode abstrak (ia memiliki beberapa metode konkret juga):
def apply(v1: T1, v2: T2): R
Dan itu memberi tahu kita semua yang perlu diketahui tentang hal itu. Sebuah fungsi memiliki apply
metode yang menerima N parameter jenis T1 , T2 , ..., TN , dan kembali sesuatu dari jenis R
. Ini bertentangan pada parameter yang diterimanya, dan ko-varian pada hasilnya.
Varians itu berarti bahwa a Function1[Seq[T], String]
adalah subtipe dari Function1[List[T], AnyRef]
. Menjadi subtipe berarti dapat digunakan sebagai pengganti . Orang dapat dengan mudah melihat bahwa jika saya akan menelepon f(List(1, 2, 3))
dan mengharapkan AnyRef
kembali, salah satu dari dua jenis di atas akan berfungsi.
Sekarang, apa kesamaan metode dan fungsi? Nah, jika f
fungsi dan m
metode lokal untuk ruang lingkup, maka keduanya bisa disebut seperti ini:
val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))
Panggilan-panggilan ini sebenarnya berbeda, karena yang pertama hanyalah gula sintaksis. Scala mengembangkannya ke:
val o1 = f.apply(List(1, 2, 3))
Yang, tentu saja, adalah pemanggilan metode pada objek f
. Fungsinya juga memiliki gula sintaksis lainnya untuk keuntungannya: fungsi literal (sebenarnya dua di antaranya) dan (T1, T2) => R
ketik tanda tangan. Sebagai contoh:
val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
case i: Int => "Int"
case d: Double => "Double"
case o => "Other"
}
Kesamaan lain antara metode dan fungsi adalah bahwa yang pertama dapat dengan mudah dikonversi menjadi yang terakhir:
val f = m _
Scala akan memperluas itu , dengan asumsi m
tipe (List[Int])AnyRef
menjadi (Scala 2.7):
val f = new AnyRef with Function1[List[Int], AnyRef] {
def apply(x$1: List[Int]) = this.m(x$1)
}
Pada Scala 2.8, ini sebenarnya menggunakan AbstractFunction1
kelas untuk mengurangi ukuran kelas.
Perhatikan bahwa seseorang tidak dapat mengonversi sebaliknya - dari suatu fungsi ke metode.
Metode, bagaimanapun, memiliki satu keuntungan besar (baik, dua - mereka bisa sedikit lebih cepat): mereka dapat menerima parameter tipe . Misalnya, sementara di f
atas dapat menentukan jenis List
yang diterimanya ( List[Int]
dalam contoh), m
dapat parameterisasi:
def m[T](l: List[T]): String = l mkString ""
Saya pikir ini cukup banyak mencakup segalanya, tetapi saya akan dengan senang hati melengkapi ini dengan jawaban atas pertanyaan yang mungkin tersisa.
val f = m
oleh kompiler seperti yang val f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }
Anda harus tunjukkan bahwa di this
dalam apply
metode tidak merujuk ke AnyRef
objek, tetapi ke objek yang metodenya val f = m _
dievaluasi ( luar this
, jadi bisa dikatakan ), karena this
berada di antara nilai-nilai yang ditangkap oleh penutupan (seperti misalnya return
seperti yang ditunjukkan di bawah).
Satu perbedaan praktis besar antara metode dan fungsi adalah apa return
artinya. return
hanya pernah kembali dari suatu metode. Sebagai contoh:
scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
val f = () => { return "test" }
^
Kembali dari fungsi yang didefinisikan dalam suatu metode menghasilkan pengembalian non-lokal:
scala> def f: String = {
| val g = () => { return "test" }
| g()
| "not this"
| }
f: String
scala> f
res4: String = test
Sedangkan kembali dari metode lokal hanya kembali dari metode itu.
scala> def f2: String = {
| def g(): String = { return "test" }
| g()
| "is this"
| }
f2: String
scala> f2
res5: String = is this
for (a <- List(1, 2, 3)) { return ... }
? Itu akan ditutup untuk penutupan.
return
mengembalikan nilai dari fungsi, dan beberapa bentuk escape
atau break
atau continue
untuk kembali dari metode.
function Suatu fungsi dapat dipanggil dengan daftar argumen untuk menghasilkan suatu hasil. Fungsi memiliki daftar parameter, badan, dan tipe hasil. Fungsi yang merupakan anggota dari kelas, sifat, atau objek tunggal disebut metode . Fungsi yang didefinisikan di dalam fungsi lain disebut fungsi lokal. Fungsi dengan tipe hasil Unit disebut prosedur. Fungsi anonim dalam kode sumber disebut literal fungsi. Pada saat dijalankan, fungsi literal dipakai menjadi objek yang disebut nilai fungsi.
Pemrograman dalam Scala Edisi Kedua. Martin Odersky - Lex Spoon - Bill Venners
Katakanlah Anda memiliki Daftar
scala> val x =List.range(10,20)
x: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
Tentukan Metode
scala> def m1(i:Int)=i+2
m1: (i: Int)Int
Tentukan Fungsi
scala> (i:Int)=>i+2
res0: Int => Int = <function1>
scala> x.map((x)=>x+2)
res2: List[Int] = List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
Metode Menerima Argumen
scala> m1(2)
res3: Int = 4
Mendefinisikan Fungsi dengan val
scala> val p =(i:Int)=>i+2
p: Int => Int = <function1>
Argumen untuk fungsi adalah Opsional
scala> p(2)
res4: Int = 4
scala> p
res5: Int => Int = <function1>
Argumen untuk Metode adalah Wajib
scala> m1
<console>:9: error: missing arguments for method m1;
follow this method with `_' if you want to treat it as a partially applied function
Periksa Tutorial berikut yang menjelaskan lewat perbedaan lain dengan contoh-contoh seperti contoh lain dari diff dengan Fungsi Metode Vs, Menggunakan fungsi sebagai Variabel, membuat fungsi yang mengembalikan fungsi
Ada artikel bagus di sini dari mana sebagian besar deskripsi saya diambil. Hanya perbandingan singkat dari Fungsi dan Metode mengenai pemahaman saya. Semoga ini bisa membantu:
Fungsi : Mereka pada dasarnya adalah objek. Lebih tepatnya, fungsi adalah objek dengan metode yang berlaku; Oleh karena itu, mereka sedikit lebih lambat daripada metode karena overhead mereka. Ini mirip dengan metode statis dalam arti bahwa mereka tidak tergantung pada objek yang akan dipanggil. Contoh sederhana dari suatu fungsi adalah seperti di bawah ini:
val f1 = (x: Int) => x + x
f1(2) // 4
Baris di atas tidak lain adalah menugaskan satu objek ke objek lain seperti object1 = object2. Sebenarnya object2 dalam contoh kita adalah fungsi anonim dan sisi kiri mendapatkan jenis objek karena itu. Karena itu, sekarang f1 adalah objek (Fungsi). Fungsi anonim sebenarnya adalah instance dari Function1 [Int, Int] yang berarti fungsi dengan 1 parameter tipe Int dan mengembalikan nilai tipe Int. Memanggil f1 tanpa argumen akan memberi kita tanda tangan dari fungsi anonim (Int => Int =)
Metode : Mereka bukan objek tetapi ditugaskan ke instance kelas, yaitu objek. Persis sama dengan metode di java atau fungsi anggota dalam c ++ (seperti yang ditunjukkan oleh Raffi Khatchadourian dalam komentar untuk pertanyaan ini ) dan lain-lain. Contoh sederhana dari sebuah metode sama seperti di bawah ini:
def m1(x: Int) = x + x
m1(2) // 4
Baris di atas bukanlah penetapan nilai sederhana tetapi definisi metode. Ketika Anda memanggil metode ini dengan nilai 2 seperti baris kedua, x diganti dengan 2 dan hasilnya akan dihitung dan Anda mendapatkan 4 sebagai output. Di sini Anda akan mendapatkan kesalahan jika cukup menulis m1 karena ini adalah metode dan perlu nilai input. Dengan menggunakan _ Anda dapat menetapkan metode ke fungsi seperti di bawah ini:
val f2 = m1 _ // Int => Int = <function1>
Ini adalah posting yang bagus dari Rob Norris yang menjelaskan perbedaannya, ini adalah TL; DR
Metode dalam Scala bukan nilai, tetapi fungsi. Anda dapat membangun fungsi yang mendelegasikan metode menggunakan η-ekspansi (dipicu oleh trailing undererscore thingy).
dengan definisi berikut:
sebuah metode adalah sesuatu yang didefinisikan dengan def dan nilai adalah sesuatu yang Anda dapat menetapkan ke val
Singkatnya ( ekstrak dari blog ):
Ketika kita mendefinisikan suatu metode, kita melihat bahwa kita tidak dapat menetapkannya ke a val
.
scala> def add1(n: Int): Int = n + 1
add1: (n: Int)Int
scala> val f = add1
<console>:8: error: missing arguments for method add1;
follow this method with `_' if you want to treat it as a partially applied function
val f = add1
Perhatikan juga jenis dari add1
yang tidak terlihat normal; Anda tidak dapat mendeklarasikan variabel tipe (n: Int)Int
. Metode bukanlah nilai.
Namun, dengan menambahkan operator postfix-ekspansi (η diucapkan “eta”), kita dapat mengubah metode menjadi nilai fungsi. Perhatikan jenis f
.
scala> val f = add1 _
f: Int => Int = <function1>
scala> f(3)
res0: Int = 4
Efeknya _
adalah untuk melakukan yang setara dari yang berikut: kami membangun sebuah Function1
instance yang mendelegasikan ke metode kami.
scala> val g = new Function1[Int, Int] { def apply(n: Int): Int = add1(n) }
g: Int => Int = <function1>
scala> g(3)
res18: Int = 4
Dalam Scala 2.13, tidak seperti fungsi, metode dapat mengambil / kembali
Namun, pembatasan ini diangkat dalam dotty (Scala 3) oleh tipe fungsi Polymorphic # 4672 , misalnya, dotty versi 0.23.0-RC1 memungkinkan sintaks berikut
Ketikkan parameter
def fmet[T](x: List[T]) = x.map(e => (e, e))
val ffun = [T] => (x: List[T]) => x.map(e => (e, e))
Parameter implisit ( parameter konteks )
def gmet[T](implicit num: Numeric[T]): T = num.zero
val gfun: [T] => Numeric[T] ?=> T = [T] => (using num: Numeric[T]) => num.zero
Jenis tergantung
class A { class B }
def hmet(a: A): a.B = new a.B
val hfun: (a: A) => a.B = hmet
Untuk contoh lebih lanjut, lihat tes / jalankan / polymorphic-functions.scala
Secara praktis, seorang programmer Scala hanya perlu mengetahui tiga aturan berikut untuk menggunakan fungsi dan metode dengan benar:
def
dan fungsi literal yang didefinisikan oleh =>
adalah fungsi. Ini didefinisikan di halaman 143, Bab 8 dalam buku Programming in Scala, edisi ke-4.someNumber.foreach(println)
Setelah empat edisi Pemrograman dalam Scala, masih menjadi masalah bagi orang untuk membedakan dua konsep penting: fungsi dan nilai fungsi karena semua edisi tidak memberikan penjelasan yang jelas. Spesifikasi bahasa terlalu rumit. Saya menemukan aturan di atas sederhana dan akurat.