Apa saja fitur tersembunyi Scala yang harus diperhatikan oleh setiap pengembang Scala?
Tolong, satu fitur tersembunyi per jawaban.
scala
hidden-features
Krzysiek Goj
sumber
sumber
Jawaban:
Oke, saya harus menambahkan satu lagi. Setiap
Regex
objek di Scala memiliki extractor (lihat jawaban dari oxbox_lakes di atas) yang memberi Anda akses ke grup pertandingan. Jadi Anda dapat melakukan sesuatu seperti:Baris kedua terlihat membingungkan jika Anda tidak terbiasa menggunakan pencocokan pola dan ekstraktor. Setiap kali Anda mendefinisikan
val
atauvar
, apa yang muncul setelah kata kunci bukan hanya pengidentifikasi melainkan sebuah pola. Itu sebabnya ini bekerja:Ekspresi tangan kanan membuat
Tuple3[Int, Double, String]
yang dapat cocok dengan pola(a, b, c)
.Sebagian besar waktu pola Anda menggunakan ekstraktor yang merupakan anggota objek tunggal. Misalnya, jika Anda menulis pola suka
maka Anda secara implisit memanggil ekstraktor
Some.unapply
.Tetapi Anda juga dapat menggunakan instance kelas dalam pola, dan itulah yang terjadi di sini. Val regex adalah turunan dari
Regex
, dan ketika Anda menggunakannya dalam suatu pola, Anda secara implisit memanggilregex.unapplySeq
(unapply
versusunapplySeq
berada di luar cakupan jawaban ini), yang mengekstraksi grup pertandingan menjadi aSeq[String]
, elemen-elemen yang ditugaskan untuk variabel tahun, bulan, dan hari.sumber
Definisi tipe struktural - yaitu tipe yang dijelaskan oleh metode apa yang didukungnya. Sebagai contoh:
Perhatikan bahwa tipe parameter
closeable
tidak didefinisikan selain memilikiclose
metodesumber
Tipe-Konstruktor Polimorfisme (alias tipe yang lebih tinggi)
Tanpa fitur ini, Anda dapat, misalnya, mengekspresikan ide memetakan fungsi pada daftar untuk mengembalikan daftar lain, atau memetakan fungsi pada pohon untuk mengembalikan pohon lain. Tetapi Anda tidak dapat mengungkapkan ide ini secara umum tanpa jenis yang lebih tinggi.
Dengan jenis yang lebih tinggi, Anda dapat menangkap gagasan jenis apa pun yang diparameterisasi dengan jenis lain. Tipe konstruktor yang mengambil satu parameter dikatakan sejenis
(*->*)
. Sebagai contohList
,. Tipe konstruktor yang mengembalikan tipe konstruktor lain dikatakan sejenis(*->*->*)
. Sebagai contohFunction1
,. Tetapi dalam Scala, kami memiliki jenis yang lebih tinggi , sehingga kami dapat memiliki konstruktor tipe yang parameterised dengan konstruktor tipe lainnya. Jadi mereka seperti((*->*)->*)
.Sebagai contoh:
Sekarang, jika Anda memiliki
Functor[List]
, Anda dapat memetakan daftar. Jika Anda memilikiFunctor[Tree]
, Anda dapat memetakan di atas pohon. Tetapi yang lebih penting, jika Anda memilikiFunctor[A]
A jenis apa pun(*->*)
, Anda dapat memetakan fungsiA
.sumber
Extractors yang memungkinkan Anda untuk mengganti
if-elseif-else
kode gaya berantakan dengan pola. Saya tahu ini tidak sepenuhnya tersembunyi tetapi saya telah menggunakan Scala selama beberapa bulan tanpa benar-benar memahami kekuatan mereka. Untuk contoh (panjang) saya bisa mengganti:Dengan ini, yang jauh lebih jelas menurut saya
Saya harus melakukan sedikit kerja keras di latar belakang ...
Tetapi kerja keras itu sepadan dengan kenyataan bahwa ia memisahkan sepotong logika bisnis menjadi tempat yang masuk akal. Saya dapat menerapkan
Product.getCode
metode saya sebagai berikut ..sumber
Manifes yang merupakan semacam cara untuk mendapatkan informasi jenis saat runtime, seolah-olah Scala telah memverifikasi jenis.
sumber
Dalam scala 2.8 Anda dapat memiliki metode rekursif ekor dengan menggunakan paket scala.util.control.TailCalls (sebenarnya itu trampolining).
Sebuah contoh:
sumber
Kelas kasus secara otomatis mencampur sifat Produk, memberikan akses terindeks, terindeks ke bidang tanpa refleksi:
Fitur ini juga menyediakan cara yang disederhanakan untuk mengubah output dari
toString
metode:sumber
Ini tidak sepenuhnya tersembunyi, tetapi tentu saja fitur yang diiklankan di bawah: scalac -Xprint .
Sebagai ilustrasi penggunaan pertimbangkan sumber berikut:
Kompilasi ini dengan scalac -Xprint: output typer :
Perhatikan
scala.this.Predef.augmentString("xx").r
, yang merupakan aplikasi dariimplicit def augmentString
hadiah di Predef.scala.scalac -Xprint: <phase> akan mencetak pohon sintaks setelah beberapa fase kompiler. Untuk melihat fase yang tersedia, gunakan scalac -Xshow-phases .
Ini adalah cara yang bagus untuk mempelajari apa yang terjadi di balik layar.
Coba dengan
case class X(a:Int,b:String)
menggunakan fase typer untuk benar-benar merasakan manfaatnya.
sumber
Anda dapat menentukan struktur kontrol Anda sendiri. Ini benar-benar hanya fungsi dan objek dan beberapa gula sintaksis, tetapi mereka terlihat dan berperilaku seperti aslinya.
Misalnya, kode berikut mendefinisikan
dont {...} unless (cond)
dandont {...} until (cond)
:Sekarang Anda dapat melakukan hal berikut:
sumber
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. Membutuhkan Scalaz.@switch
anotasi dalam Scala 2.8:Contoh:
sumber
Tidak tahu apakah ini benar-benar tersembunyi, tetapi saya merasa cukup bagus.
Typeconstructors yang mengambil 2 tipe parameter dapat ditulis dalam notasi infix
sumber
var foo2barConverter: Foo ConvertTo Bar
akan membuat urutan parameter tipe menjadi jelas.Scala 2.8 memperkenalkan argumen default dan bernama, yang memungkinkan penambahan metode "copy" baru yang ditambahkan Scala ke kelas kasus. Jika Anda mendefinisikan ini:
dan Anda ingin membuat Foo baru yang seperti Foo yang ada, hanya dengan nilai "n" yang berbeda, maka Anda bisa mengatakan:
sumber
dalam scala 2.8 Anda dapat menambahkan @specialized ke kelas / metode umum Anda. Ini akan membuat versi khusus kelas untuk tipe primitif (memperluas AnyVal) dan menghemat biaya tinju / unboxing yang tidak perlu:
class Foo[@specialized T]...
Anda dapat memilih subset dari AnyVals:
class Foo[@specialized(Int,Boolean) T]...
sumber
Memperluas bahasa. Saya selalu ingin melakukan sesuatu seperti ini di Jawa (tidak bisa). Tetapi dalam Scala saya dapat memiliki:
dan kemudian menulis:
dan dapatkan
sumber
Anda dapat menetapkan parameter panggilan-dengan-nama (EDITED: ini berbeda dari parameter malas!) Ke suatu fungsi dan itu tidak akan dievaluasi sampai digunakan oleh fungsi (EDIT: pada kenyataannya, itu akan dievaluasi ulang setiap kali itu bekas). Lihat faq ini untuk detailnya
sumber
lazy val xx: Bar = x
dalam metode Anda dan sejak saat itu Anda hanya menggunakanxx
.Anda dapat menggunakan
locally
untuk memperkenalkan blok lokal tanpa menyebabkan masalah inferensi titik koma.Pemakaian:
locally
didefinisikan dalam "Predef.scala" sebagai:Menjadi sejajar, itu tidak membebankan biaya tambahan apa pun.
sumber
Inisialisasi Awal:
Keluaran:
sumber
Anda dapat membuat tipe struktural dengan kata kunci 'with'
sumber
sintaksis placeholder untuk fungsi anonim
Dari Spesifikasi Bahasa Scala:
Dari Perubahan Bahasa Scala :
Dengan ini Anda bisa melakukan sesuatu seperti:
sumber
Definisi tersirat, terutama konversi.
Misalnya, asumsikan fungsi yang akan memformat string input agar sesuai dengan ukuran, dengan mengganti bagian tengahnya dengan "...":
Anda dapat menggunakannya dengan String apa pun, dan, tentu saja, gunakan metode toString untuk mengonversi apa saja. Tapi Anda juga bisa menulisnya seperti ini:
Dan kemudian, Anda bisa lulus kelas tipe lain dengan melakukan ini:
Sekarang Anda dapat memanggil fungsi itu lewat ganda:
Argumen terakhir adalah implisit, dan diajukan secara otomatis karena deklarasi implisit de. Selanjutnya, "s" diperlakukan seperti sebuah String di dalam sizeBoundedString karena ada konversi implisit dari itu ke String.
Implikasi dari tipe ini didefinisikan lebih baik untuk tipe yang tidak umum untuk menghindari konversi yang tidak terduga. Anda juga dapat secara eksplisit melewatkan konversi, dan itu masih akan digunakan secara implisit di dalam sizeBoundedString:
Anda juga dapat memiliki beberapa argumen implisit, tetapi kemudian Anda harus melewati semuanya, atau tidak melewati salah satunya. Ada juga sintaks pintasan untuk konversi implisit:
Ini digunakan dengan cara yang persis sama.
Implikasi dapat memiliki nilai apa pun. Mereka dapat digunakan, misalnya, untuk menyembunyikan informasi perpustakaan. Ambil contoh berikut, misalnya:
Dalam contoh ini, memanggil "f" dalam objek Y akan mengirim log ke daemon default, dan pada instance X ke daemon X Daemon. Tetapi memanggil g pada instance X akan mengirim log ke DefaultDaemon yang diberikan secara eksplisit.
Sementara contoh sederhana ini dapat ditulis ulang dengan overload dan private state, implisit tidak memerlukan private state, dan dapat dibawa ke dalam konteks dengan impor.
sumber
Mungkin tidak terlalu tersembunyi, tapi saya pikir ini berguna:
Ini akan secara otomatis menghasilkan pengambil dan penyetel untuk bidang yang cocok dengan konvensi kacang.
Penjelasan lebih lanjut di developerworks
sumber
Argumen implisit dalam penutupan.
Argumen fungsi dapat ditandai sebagai implisit seperti halnya metode. Dalam ruang lingkup fungsi fungsi parameter implisit terlihat dan memenuhi syarat untuk resolusi implisit:
sumber
Bangun struktur data tanpa batas dengan Scala's
Stream
: http://www.codecommit.com/blog/scala/infinite-lists-for-the-fininite-patientsumber
Jenis hasil tergantung pada resolusi implisit. Ini dapat memberi Anda bentuk pengiriman ganda:
sumber
foo
penggunaan dana
yang harus ada di lingkungan sebelum pelaksanaan perintah-perintah ini. Saya menganggap Anda maksudz.perform(x)
.Setara dengan Scala untuk Java double brace initializer.
Scala memungkinkan Anda untuk membuat subclass anonim dengan tubuh kelas (konstruktor) yang berisi pernyataan untuk menginisialisasi instance kelas itu.
Pola ini sangat berguna ketika membangun antarmuka pengguna berbasis komponen (misalnya Swing, Vaadin) karena memungkinkan untuk membuat komponen UI dan mendeklarasikan propertinya lebih ringkas.
Lihat http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf untuk informasi lebih lanjut.
Berikut adalah contoh membuat tombol Vaadin:
sumber
Tidak termasuk anggota dari
import
pernyataanMisalkan Anda ingin menggunakan
Logger
yang berisi aprintln
danprinterr
metode, tetapi Anda hanya ingin menggunakan yang untuk pesan kesalahan, dan menyimpan yang lama baikPredef.println
untuk keluaran standar. Anda bisa melakukan ini:tetapi jika
logger
juga mengandung dua belas metode lain yang ingin Anda impor dan gunakan, menjadi tidak nyaman untuk mendaftarnya. Anda bisa mencoba:tetapi ini masih "mencemari" daftar anggota yang diimpor. Masukkan wildcard kuat über:
dan itu akan melakukan hal yang benar ™.
sumber
require
metode (didefinisikan dalamPredef
) yang memungkinkan Anda untuk mendefinisikan kendala fungsi tambahan yang akan diperiksa selama waktu berjalan. Bayangkan Anda sedang mengembangkan klien twitter lain dan Anda perlu membatasi panjang tweet hingga 140 simbol. Selain itu Anda tidak dapat memposting tweet kosong.Sekarang memanggil pos dengan argumen panjang yang tidak sesuai akan menyebabkan pengecualian:
Anda dapat menulis beberapa persyaratan atau bahkan menambahkan deskripsi ke masing-masing:
Sekarang pengecualian bertele-tele:
Satu contoh lagi ada di sini .
Bonus
Anda dapat melakukan tindakan setiap kali persyaratan gagal:
sumber
require
bukan kata yang dilindungi undang-undang. Ini hanyalah metode yang didefinisikan dalamPredef
.Ciri-ciri dengan
abstract override
metode adalah fitur dalam Scala yang tidak banyak diiklankan seperti halnya banyak lainnya. Maksud dari metode denganabstract override
pengubah adalah untuk melakukan beberapa operasi dan mendelegasikan panggilan kesuper
. Maka sifat-sifat ini harus dicampur dengan implementasi konkret dariabstract override
metode mereka .Walaupun contoh saya benar-benar tidak lebih dari AOP orang miskin, saya menggunakan Ciri - ciri Stackable ini sesuai dengan keinginan saya untuk membangun contoh juru bahasa Scala dengan impor yang telah ditentukan sebelumnya, binding kustom, dan jalur kelas. The Stackable Traits memungkinkan untuk membuat pabrik saya sepanjang garis
new InterpreterFactory with JsonLibs with LuceneLibs
dan kemudian memiliki impor berguna dan ruang lingkup varibles untuk pengguna script.sumber