Saya mengerti hasil Ruby dan Python. Apa yang dilakukan hasil Scala?
312
Saya mengerti hasil Ruby dan Python. Apa yang dilakukan hasil Scala?
Ini digunakan dalam urutan pemahaman (seperti daftar-pemahaman dan generator Python, di mana Anda dapat menggunakan yield
juga).
Itu diterapkan dalam kombinasi dengan for
dan menulis elemen baru ke dalam urutan yang dihasilkan.
Contoh sederhana (dari scala-lang )
/** Turn command line arguments to uppercase */
object Main {
def main(args: Array[String]) {
val res = for (a <- args) yield a.toUpperCase
println("Arguments: " + res.toString)
}
}
Ekspresi yang sesuai dalam F # adalah
[ for a in args -> a.toUpperCase ]
atau
from a in args select a.toUpperCase
dalam Linq.
Ruby yield
memiliki efek yang berbeda.
Saya pikir jawaban yang diterima bagus, tetapi tampaknya banyak orang gagal memahami beberapa poin mendasar.
Pertama,
for
pemahaman Scala setara dengando
notasi Haskell , dan itu tidak lebih dari gula sintaksis untuk komposisi beberapa operasi monadik. Karena pernyataan ini kemungkinan besar tidak akan membantu siapa pun yang membutuhkan bantuan, mari kita coba lagi ... :-)for
Pemahaman Scala adalah gula sintaksis untuk komposisi beberapa operasi dengan peta,flatMap
danfilter
. Atauforeach
. Scala sebenarnya menerjemahkanfor
-expression menjadi panggilan ke metode-metode tersebut, sehingga setiap kelas yang menyediakannya, atau sebagian dari mereka, dapat digunakan untuk pemahaman.Pertama, mari kita bicara tentang terjemahannya. Ada aturan yang sangat sederhana:
Ini
diterjemahkan ke dalam
Ini
diterjemahkan ke dalam
Ini
diterjemahkan pada Scala 2.7 ke
atau, pada Scala 2.8, ke
dengan mundur ke yang pertama jika metode
withFilter
tidak tersedia tetapifilter
. Silakan lihat bagian di bawah ini untuk informasi lebih lanjut tentang ini.Ini
diterjemahkan ke dalam
Ketika Anda melihat
for
pemahaman yang sangat sederhana ,map
/foreach
alternatif terlihat, memang, lebih baik. Namun, begitu Anda mulai menyusunnya, Anda dapat dengan mudah tersesat di dalam kurung dan level sarang. Ketika itu terjadi,for
pemahaman biasanya jauh lebih jelas.Saya akan menunjukkan satu contoh sederhana, dan sengaja menghilangkan penjelasan apa pun. Anda dapat memutuskan sintaks mana yang lebih mudah dimengerti.
atau
withFilter
Scala 2.8 memperkenalkan metode yang disebut
withFilter
, yang perbedaan utamanya adalah, alih-alih mengembalikan koleksi baru yang difilter, ia memfilter sesuai permintaan. Thefilter
metode memiliki perilaku didefinisikan berdasarkan ketatnya koleksi. Untuk memahami ini lebih baik, mari kita lihat beberapa Scala 2.7 denganList
(ketat) danStream
(tidak ketat):Perbedaannya terjadi karena
filter
segera diterapkan denganList
, kembali daftar peluang - karenafound
adalahfalse
. Hanya kemudianforeach
dieksekusi, tetapi, pada saat ini, perubahanfound
tidak ada artinya, seperti yangfilter
telah dieksekusi.Dalam hal ini
Stream
, kondisi tersebut tidak segera diterapkan. Sebagai gantinya, karena setiap elemen diminta olehforeach
,filter
menguji kondisi, yang memungkinkanforeach
untuk memengaruhinyafound
. Untuk memperjelasnya, berikut ini adalah kode setara untuk pemahaman:Hal ini menyebabkan banyak masalah, karena orang-orang berharap
if
untuk dianggap sesuai permintaan, alih-alih diterapkan ke seluruh koleksi sebelumnya.Scala 2.8 diperkenalkan
withFilter
, yang selalu tidak ketat, tidak masalah ketatnya koleksi. Contoh berikut menunjukkanList
dengan kedua metode pada Scala 2.8:Ini menghasilkan hasil yang kebanyakan orang harapkan, tanpa mengubah cara
filter
berperilaku. Sebagai catatan tambahan,Range
diubah dari non-ketat menjadi ketat antara Scala 2.7 dan Scala 2.8.sumber
withFilter
seharusnya tidak ketat juga, bahkan untuk koleksi ketat, yang pantas mendapat penjelasan. Saya akan mempertimbangkan ini ...for(x <- c; y <- x; z <-y) {...}
diterjemahkan kec.foreach(x => x.foreach(y => y.foreach(z => {...})))
2.for(x <- c; y <- x; z <- y) yield {...}
diterjemahkan kec.flatMap(x => x.flatMap(y => y.map(z => {...})))
for(x <- c; y = ...) yield {...}
benar-benar diterjemahkanc.map(x => (x, ...)).map((x,y) => {...})
? Saya pikir itu diterjemahkan ke dalamc.map(x => (x, ...)).map(x => { ...use x._1 and x._2 here...})
atau saya kehilangan sesuatu?Ya, seperti yang dikatakan Earwicker, ini hampir sama dengan LINQ
select
dan sangat sedikit hubungannya dengan Ruby dan Pythonyield
. Pada dasarnya, di mana dalam C # Anda akan menulisdi Scala yang Anda miliki sebagai gantinya
Penting juga untuk memahami bahwa
for
-pengertian tidak hanya bekerja dengan urutan, tetapi dengan jenis apa pun yang mendefinisikan metode tertentu, seperti LINQ:map
, itu memungkinkanfor
-expressions yang terdiri dari satu generator.flatMap
sertamap
, memungkinkanfor
-expressions terdiri dari beberapa generator.foreach
, ia memungkinkan-for
loop tanpa hasil (baik dengan generator tunggal dan banyak).filter
, ini memungkinkanfor
ekspresi-filter yang dimulai denganif
dalamfor
ekspresi.sumber
Kecuali jika Anda mendapatkan jawaban yang lebih baik dari pengguna Scala (yang bukan saya), inilah pemahaman saya.
Itu hanya muncul sebagai bagian dari ekspresi yang dimulai dengan
for
, yang menyatakan bagaimana membuat daftar baru dari daftar yang ada.Sesuatu seperti:
Jadi ada satu item keluaran untuk setiap input (walaupun saya percaya ada cara untuk menjatuhkan duplikat).
Ini sangat berbeda dari "kelanjutan imperatif" yang dimungkinkan oleh hasil dalam bahasa lain, di mana ia menyediakan cara untuk menghasilkan daftar panjang, dari beberapa kode imperatif dengan hampir semua struktur.
(Jika Anda terbiasa dengan C #, itu lebih dekat ke operator LINQ
select
daripada ituyield return
).sumber
Kata kunci
yield
dalam Scala hanyalah gula sintaksis yang dapat dengan mudah diganti dengan amap
, seperti yang sudah dijelaskan oleh Daniel Sobral secara rinci.Di sisi lain,
yield
benar-benar menyesatkan jika Anda mencari generator (atau kelanjutan) yang mirip dengan yang ada di Python . Lihat utas SO ini untuk informasi lebih lanjut: Apa cara yang disukai untuk menerapkan 'hasil' di Scala?sumber
Pertimbangkan hal berikut untuk pemahaman
Mungkin bermanfaat untuk membacanya dengan lantang sebagai berikut
" Untuk setiap bilangan bulat
i
, jika lebih besar dari3
, maka hasilkan (hasilkan)i
dan tambahkan ke daftarA
."Dalam hal notasi set-builder matematis , pemahaman di atas adalah analog dengan
yang dapat dibaca sebagai
" Untuk setiap bilangan bulat , jika lebih besar dari , maka itu adalah anggota himpunan ."
atau sebagai alternatif
" Adalah himpunan semua bilangan bulat , sehingga masing-masing lebih besar dari ."
sumber
Yield mirip dengan untuk loop yang memiliki buffer yang tidak bisa kita lihat dan untuk setiap kenaikan, itu terus menambahkan item berikutnya ke buffer. Ketika for loop selesai berjalan, itu akan mengembalikan koleksi semua nilai yang dihasilkan. Hasil dapat digunakan sebagai operator aritmatika sederhana atau bahkan dalam kombinasi dengan array. Berikut adalah dua contoh sederhana untuk pemahaman Anda yang lebih baik
res: scala.collection.immutable.IndexedSeq [Int] = Vektor (3, 6, 9, 12, 15)
res: Seq [(Int, Char)] = Daftar ((1, a), (1, b), (1, c), (2, a), (2, b), (2, c), ( 3, a), (3, b), (3, c))
Semoga ini membantu!!
sumber
Kedua kode ini setara.
Kedua kode ini juga setara.
Peta sefleksibel hasil dan sebaliknya.
sumber
hasil lebih fleksibel daripada peta (), lihat contoh di bawah ini
hasil akan mencetak hasil seperti: Daftar (5, 6), yang bagus
sedangkan map () akan mengembalikan hasil seperti: Daftar (false, false, true, true, true), yang mungkin bukan yang Anda inginkan.
sumber