Saya pernah mencoba menulis tentang ini, tetapi pada akhirnya saya menyerah, karena aturannya agak kabur. Pada dasarnya, Anda harus memahami itu.
Mungkin yang terbaik adalah berkonsentrasi di mana kurung kurawal dan kurung dapat digunakan secara bergantian: ketika melewati parameter ke pemanggilan metode. Anda dapat mengganti tanda kurung dengan kurung kurawal jika, dan hanya jika, metode mengharapkan parameter tunggal. Sebagai contoh:
List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter
List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter
Namun, masih ada lagi yang perlu Anda ketahui untuk lebih memahami aturan-aturan ini.
Peningkatan pemeriksaan kompilasi dengan parens
Para penulis dari Spray merekomendasikan round parens karena mereka memberikan peningkatan pemeriksaan kompilasi. Ini sangat penting untuk DSL seperti Spray. Dengan menggunakan parens, Anda memberi tahu kompiler bahwa itu hanya boleh diberikan satu baris; karena itu jika Anda secara tidak sengaja memberikannya dua atau lebih, itu akan mengeluh. Sekarang ini bukan masalahnya dengan kurung kurawal - jika misalnya Anda lupa operator di suatu tempat, maka kode Anda akan dikompilasi, dan Anda mendapatkan hasil yang tidak terduga dan berpotensi bug yang sangat sulit ditemukan. Di bawah ini dibuat-buat (karena ekspresinya murni dan setidaknya akan memberi peringatan), tetapi jelaskan:
method {
1 +
2
3
}
method(
1 +
2
3
)
Kompilasi pertama, yang kedua memberi error: ')' expected but integer literal found
. Penulis ingin menulis 1 + 2 + 3
.
Orang bisa berpendapat bahwa ini serupa untuk metode multi-parameter dengan argumen default; tidak mungkin untuk secara tidak sengaja melupakan koma untuk memisahkan parameter ketika menggunakan parens.
Verbositas
Catatan penting yang sering diabaikan tentang verbositas. Menggunakan kurung kurawal pasti mengarah ke kode verbose karena panduan gaya Scala dengan jelas menyatakan bahwa kurung kurawal harus berada di jalurnya sendiri:
… Kurung penutup berada pada barisnya sendiri segera setelah baris terakhir dari fungsi.
Banyak pemformat ulang otomatis, seperti di IntelliJ, akan secara otomatis melakukan pemformatan ulang ini untuk Anda. Jadi cobalah untuk tetap menggunakan parens bulat ketika Anda bisa.
Notasi Infix
Saat menggunakan notasi infiks, seperti List(1,2,3) indexOf (2)
Anda dapat menghilangkan tanda kurung jika hanya ada satu parameter dan tulis sebagai List(1, 2, 3) indexOf 2
. Ini bukan kasus notasi titik.
Perhatikan juga bahwa ketika Anda memiliki parameter tunggal yang merupakan ekspresi multi-token, seperti x + 2
atau a => a % 2 == 0
, Anda harus menggunakan tanda kurung untuk menunjukkan batas-batas ekspresi.
Tuples
Karena terkadang Anda dapat menghilangkan tanda kurung, terkadang tupel membutuhkan tanda kurung tambahan seperti dalam ((1, 2))
, dan terkadang tanda kurung luar dapat dihilangkan, seperti di (1, 2)
. Ini dapat menyebabkan kebingungan.
Function / Partial Function literals dengan case
Scala memiliki sintaks untuk fungsi dan fungsi literal fungsi. Ini terlihat seperti ini:
{
case pattern if guard => statements
case pattern => statements
}
Satu-satunya tempat lain di mana Anda dapat menggunakan case
pernyataan adalah dengan match
dan catch
kata kunci:
object match {
case pattern if guard => statements
case pattern => statements
}
try {
block
} catch {
case pattern if guard => statements
case pattern => statements
} finally {
block
}
Anda tidak dapat menggunakan case
pernyataan dalam konteks lain apa pun . Jadi, jika Anda ingin menggunakannya case
, Anda perlu kurung kurawal. Jika Anda bertanya-tanya apa yang membuat perbedaan antara fungsi dan fungsi parsial literal, jawabannya adalah: konteks. Jika Scala mengharapkan fungsi, fungsi yang Anda dapatkan. Jika mengharapkan fungsi parsial, Anda mendapatkan fungsi parsial. Jika keduanya diharapkan, ini memberikan kesalahan tentang ambiguitas.
Ekspresi dan Blok
Parenthesis dapat digunakan untuk membuat subekspresi. Kurung kurawal dapat digunakan untuk membuat blok kode (ini bukan fungsi literal, jadi berhati-hatilah untuk mencoba menggunakannya seperti satu). Blok kode terdiri dari beberapa pernyataan, yang masing-masing dapat berupa pernyataan impor, deklarasi atau ekspresi. Bunyinya seperti ini:
{
import stuff._
statement ; // ; optional at the end of the line
statement ; statement // not optional here
var x = 0 // declaration
while (x < 10) { x += 1 } // stuff
(x % 5) + 1 // expression
}
( expression )
Jadi, jika Anda membutuhkan deklarasi, banyak pernyataan, import
atau semacamnya, Anda perlu kurung kurawal. Dan karena ekspresi adalah pernyataan, tanda kurung dapat muncul di dalam kurung kurawal. Tetapi yang menarik adalah blok kode juga merupakan ekspresi, sehingga Anda dapat menggunakannya di mana saja di dalam ekspresi:
( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1
Jadi, karena ekspresi adalah pernyataan, dan blok kode adalah ekspresi, semuanya di bawah ini valid:
1 // literal
(1) // expression
{1} // block of code
({1}) // expression with a block of code
{(1)} // block of code with an expression
({(1)}) // you get the drift...
Di mana mereka tidak bisa dipertukarkan
Pada dasarnya, Anda tidak dapat mengganti {}
dengan ()
atau sebaliknya di tempat lain. Sebagai contoh:
while (x < 10) { x += 1 }
Ini bukan panggilan metode, jadi Anda tidak dapat menulisnya dengan cara lain. Nah, Anda bisa meletakkan kurung kurawal di dalam tanda kurung untuk condition
, serta menggunakan kurung kurung di dalam kurung kurawal untuk blok kode:
while ({x < 10}) { (x += 1) }
Jadi, saya harap ini membantu.
{}
- semuanya harus menjadi ekspresi murni tunggalList{1, 2, 3}.reduceLeft(_ + _)
tidak valid, apakah maksud Anda memiliki sintaks yang salah? Tetapi saya menemukan bahwa kode dapat dikompilasi. Saya meletakkan kode saya di siniList(1, 2, 3)
semua contoh, alih-alihList{1, 2, 3}
. Sayangnya, pada versi Scala saat ini (2.13), ini gagal dengan pesan kesalahan yang berbeda (koma yang tak terduga). Anda harus kembali ke 2,7 atau 2,8 untuk mendapatkan kesalahan awal, mungkin.Ada beberapa aturan dan kesimpulan yang berbeda yang terjadi di sini: pertama-tama, Scala menyimpulkan kawat gigi ketika parameter adalah fungsi, misalnya dalam
list.map(_ * 2)
kawat gigi disimpulkan, itu hanya bentuk yang lebih pendeklist.map({_ * 2})
. Kedua, Scala memungkinkan Anda untuk melewati tanda kurung pada daftar parameter terakhir, jika daftar parameter tersebut memiliki satu parameter dan itu adalah fungsi, sehinggalist.foldLeft(0)(_ + _)
dapat ditulis sebagailist.foldLeft(0) { _ + _ }
(ataulist.foldLeft(0)({_ + _})
jika Anda ingin menjadi lebih eksplisit).Namun, jika Anda menambahkan
case
Anda mendapatkan, seperti yang telah disebutkan orang lain, fungsi parsial bukan fungsi, dan Scala tidak akan menyimpulkan kurung kurawal untuk fungsi parsial, jadilist.map(case x => x * 2)
tidak akan berfungsi, tetapi keduanyalist.map({case x => 2 * 2})
danlist.map { case x => x * 2 }
akan.sumber
list.foldLeft{0}{_+_}
berfungsi.Ada upaya dari komunitas untuk membakukan penggunaan kawat gigi dan tanda kurung, lihat Panduan Gaya Scala (halaman 21): http://www.codecommit.com/scala-style-guide.pdf
Sintaks yang disarankan untuk pemanggilan metode tingkat tinggi adalah selalu menggunakan tanda kurung, dan untuk melewati titik:
Untuk panggilan metod "normal", Anda harus menggunakan titik dan tanda kurung.
sumber
+
,--
), BUKAN metode biasa sepertitakeWhile
. Seluruh titik notasi infiks adalah untuk memungkinkan DSL dan operator kustom, oleh karena itu kita harus menggunakannya dalam konteks ini tidak sepanjang waktu.Saya tidak berpikir ada sesuatu yang khusus atau kompleks tentang kurung kurawal di Scala. Untuk menguasai penggunaan yang tampaknya rumit di Scala, ingatlah beberapa hal sederhana:
Mari kita jelaskan beberapa contoh per tiga aturan di atas:
sumber
{}
perilaku tersebut. Saya telah memperbarui kata-kata untuk presisi. Dan untuk 4, ini sedikit rumit karena interaksi antara()
dan{}
, sebagaidef f(x: Int): Int = f {x}
karya, dan itulah sebabnya saya punya yang ke-5. :)fun f(x) = f x
berlaku di SML.f {x}
sebagaif({x})
tampaknya menjadi penjelasan yang lebih baik bagi saya, karena pemikiran()
dan{}
dipertukarkan kurang intuitif. Omong-omong,f({x})
interpretasinya agak didukung oleh Scala spec (bagian 6.6):ArgumentExprs ::= ‘(’ [Exprs] ‘)’ | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ’)’ | [nl] BlockExp
Saya pikir perlu dijelaskan penggunaannya dalam pemanggilan fungsi dan mengapa berbagai hal terjadi. Seperti seseorang sudah mengatakan kurung kurawal mendefinisikan blok kode, yang juga merupakan ekspresi sehingga dapat diletakkan di mana ekspresi diharapkan dan itu akan dievaluasi. Ketika dievaluasi, pernyataannya dieksekusi dan nilai pernyataan terakhir adalah hasil dari evaluasi seluruh blok (agak seperti di Ruby).
Setelah itu kita dapat melakukan hal-hal seperti:
Contoh terakhir hanyalah pemanggilan fungsi dengan tiga parameter, yang masing-masing dievaluasi terlebih dahulu.
Sekarang untuk melihat cara kerjanya dengan pemanggilan fungsi mari kita mendefinisikan fungsi sederhana yang mengambil fungsi lain sebagai parameter.
Untuk memanggilnya, kita perlu melewati fungsi yang mengambil satu param dari tipe Int, jadi kita bisa menggunakan fungsi literal dan meneruskannya ke foo:
Sekarang seperti yang dikatakan sebelumnya kita dapat menggunakan blok kode sebagai ganti ekspresi jadi mari kita gunakan itu
Apa yang terjadi di sini adalah bahwa kode di dalam {} dievaluasi, dan nilai fungsi dikembalikan sebagai nilai evaluasi blok, nilai ini kemudian diteruskan ke foo. Secara semantik ini sama dengan panggilan sebelumnya.
Tetapi kita dapat menambahkan sesuatu lagi:
Sekarang blok kode kita berisi dua pernyataan, dan karena itu dievaluasi sebelum foo dieksekusi, yang terjadi adalah yang pertama "Hei" dicetak, lalu fungsi kita diteruskan ke foo, "Memasukkan foo" dicetak dan terakhir "4" dicetak .
Ini terlihat agak jelek dan Scala memungkinkan kita untuk melewati tanda kurung dalam kasus ini, sehingga kita dapat menulis:
atau
Itu terlihat jauh lebih bagus dan setara dengan yang sebelumnya. Di sini masih blok kode dievaluasi terlebih dahulu dan hasil evaluasi (yaitu x => println (x)) diteruskan sebagai argumen ke foo.
sumber
foo({ x => println(x) })
. Mungkin saya terlalu terjebak dalam cara saya ...Karena Anda menggunakan
case
, Anda mendefinisikan fungsi parsial dan fungsi parsial memerlukan kurung kurawal.sumber
Peningkatan pemeriksaan kompilasi dengan parens
Para penulis Spray, merekomendasikan bahwa parens bulat memberikan peningkatan pemeriksaan kompilasi. Ini sangat penting untuk DSL seperti Spray. Dengan menggunakan parens, Anda memberi tahu kompiler bahwa itu hanya boleh diberikan satu baris, oleh karena itu jika Anda tidak sengaja memberikannya dua atau lebih, ia akan mengeluh. Sekarang ini bukan masalahnya dengan kurung kurawal, jika misalnya, Anda lupa operator di mana kode Anda akan dikompilasi, Anda mendapatkan hasil yang tidak terduga dan berpotensi menemukan bug yang sangat sulit. Di bawah ini dibikin (karena ekspresinya murni dan setidaknya akan memberi peringatan), tetapi jelaskan
Kompilasi pertama, yang kedua memberi
error: ')' expected but integer literal found.
penulis ingin menulis1 + 2 + 3
.Orang bisa berpendapat bahwa ini serupa untuk metode multi-parameter dengan argumen default; tidak mungkin untuk secara tidak sengaja melupakan koma untuk memisahkan parameter ketika menggunakan parens.
Verbositas
Catatan penting yang sering diabaikan tentang verbositas. Menggunakan kurung kurawal pasti mengarah ke kode verbose karena panduan gaya scala jelas menyatakan bahwa kurawal kurung kurawal harus pada baris mereka sendiri: http://docs.scala-lang.org/style/declarations.html "... kurung penutup ada pada barisnya sendiri segera setelah baris terakhir dari fungsi. " Banyak pemformat ulang otomatis, seperti di Intellij, akan secara otomatis melakukan pemformatan ulang ini untuk Anda. Jadi cobalah untuk tetap menggunakan parens bulat ketika Anda bisa. Misalnya
List(1, 2, 3).reduceLeft{_ + _}
menjadi:sumber
Dengan kawat gigi, Anda mendapat tanda koma untuk Anda dan kurung tidak. Pertimbangkan
takeWhile
fungsi, karena mengharapkan fungsi parsial, hanya{case xxx => ??? }
definisi yang valid alih-alih tanda kurung di sekitar ekspresi kasus.sumber