Saya sedang mencari cara melalui tutorial Scala playframework dan saya menemukan potongan kode ini yang membuat saya bingung:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
Jadi saya memutuskan untuk menyelidiki dan menemukan posting ini .
Saya masih belum mengerti.
Apa perbedaan antara ini:
implicit def double2Int(d : Double) : Int = d.toInt
dan
def double2IntNonImplicit(d : Double) : Int = d.toInt
selain fakta yang jelas mereka memiliki nama metode yang berbeda.
Kapan saya harus menggunakan implicit
dan mengapa?
scala
syntax
playframework
keyword
Clive
sumber
sumber
Jawaban:
Saya akan menjelaskan kasus penggunaan utama dari implisit di bawah ini, tetapi untuk lebih jelasnya lihat bab Pemrograman yang relevan di Scala .
Parameter implisit
Daftar parameter akhir pada suatu metode dapat ditandai
implicit
, yang berarti nilai-nilai akan diambil dari konteks di mana mereka dipanggil. Jika tidak ada nilai implisit dari tipe yang tepat dalam cakupan, itu tidak akan dikompilasi. Karena nilai implisit harus diselesaikan ke nilai tunggal dan untuk menghindari bentrokan, itu ide yang baik untuk membuat tipe spesifik untuk tujuannya, misalnya tidak memerlukan metode Anda untuk menemukan implisitInt
!contoh:
Konversi tersirat
Ketika kompiler menemukan ekspresi tipe yang salah untuk konteks, ia akan mencari
Function
nilai implisit dari tipe yang akan memungkinkannya untuk mengetik centang. Jadi jika suatuA
diperlukan dan ia menemukan aB
, ia akan mencari nilai implisit dari tipeB => A
dalam lingkup (ia juga memeriksa beberapa tempat lain seperti dalamB
danA
objek pendamping, jika ada). Karenadef
s dapat "eta-diperluas" menjadiFunction
objek, sebuahimplicit def xyz(arg: B): A
akan melakukannya juga.Jadi perbedaan antara metode Anda adalah bahwa yang ditandai
implicit
akan dimasukkan untuk Anda oleh kompiler ketikaDouble
ditemukan tetapiInt
diperlukan.akan bekerja sama dengan
Pada detik kami telah memasukkan konversi secara manual; pada awalnya kompiler melakukan hal yang sama secara otomatis. Konversi diperlukan karena anotasi jenis di sisi kiri.
Mengenai cuplikan pertama Anda dari Play:
Tindakan dijelaskan pada halaman ini dari dokumentasi Play (lihat juga API docs ). Anda menggunakan
pada
Action
objek (yang merupakan pendamping untuk sifat dengan nama yang sama).Jadi kita perlu menyediakan Fungsi sebagai argumen, yang dapat ditulis sebagai bentuk literal
Dalam fungsi literal, bagian sebelum
=>
adalah deklarasi nilai, dan dapat ditandaiimplicit
jika Anda mau, sama sepertival
deklarasi lainnya . Di sini,request
tidak harus ditandaiimplicit
untuk ini untuk mengetikkan cek, tetapi dengan melakukan itu akan tersedia sebagai nilai implisit untuk setiap metode yang mungkin membutuhkannya dalam fungsi (dan tentu saja, itu dapat digunakan secara eksplisit juga) . Dalam kasus khusus ini, ini telah dilakukan karenabindFromRequest
metode pada kelas Formulir memerlukanRequest
argumen implisit .sumber
PERINGATAN: mengandung sarkasme dengan bijaksana! YMMV ...
Jawaban Luigi lengkap dan benar. Yang ini hanya sedikit memperluasnya dengan contoh bagaimana Anda dapat menggunakan terlalu banyak implisit , seperti yang sering terjadi dalam proyek Scala. Sebenarnya sangat sering, Anda bahkan dapat menemukannya di salah satu panduan "Praktik Terbaik" .
sumber
Mengapa dan kapan Anda harus menandai
request
parameter sebagaiimplicit
:Beberapa metode yang akan Anda gunakan dalam tubuh tindakan Anda memiliki daftar parameter implisit seperti, misalnya, Form.scala mendefinisikan metode:
Anda tidak perlu melihat ini karena Anda hanya akan menelepon
myForm.bindFromRequest()
Anda tidak harus memberikan argumen implisit secara eksplisit. Tidak, Anda meninggalkan kompiler untuk mencari objek kandidat yang valid untuk lulus setiap kali menemukan panggilan metode yang membutuhkan instance dari permintaan. Karena Anda lakukan memiliki permintaan yang tersedia, semua yang perlu Anda lakukan adalah untuk menandainya sebagaiimplicit
.Anda secara eksplisit menandainya sebagai tersedia untuk penggunaan implisit .
Anda memberi tahu kompiler bahwa "OK" untuk menggunakan objek permintaan yang dikirim oleh kerangka kerja Play (bahwa kami memberikan nama "permintaan" tetapi bisa saja menggunakan "r" atau "req") di mana saja diperlukan, "diam-diam" .
lihat itu? itu tidak ada, tapi itu adalah ada!
Itu hanya terjadi tanpa Anda harus memasukkannya secara manual di setiap tempat yang dibutuhkan (tetapi Anda dapat meneruskannya secara eksplisit, jika Anda mau, tidak peduli apakah itu ditandai
implicit
atau tidak):Tanpa menandainya sebagai implisit, Anda harus melakukan hal di atas. Menandainya sebagai implisit Anda tidak harus melakukannya.
Kapan Anda harus menandai permintaan sebagai
implicit
? Anda hanya perlu jika Anda menggunakan metode yang menyatakan daftar parameter implisit yang mengharapkan instance dari Permintaan . Tetapi untuk membuatnya sederhana, Anda bisa membiasakan diri untukimplicit
selalu menandai permintaan . Dengan begitu Anda bisa menulis kode singkat yang indah.sumber
Dalam scala implisit berfungsi sebagai :
Konverter
Nilai parameter injektor
Ada 3 jenis penggunaan Implisit
Konversi jenis tersirat : Ini mengkonversi tugas memproduksi kesalahan menjadi tipe yang dimaksud
val x: String = "1"
val y: Int = x
String bukan sub tipe Int , jadi kesalahan terjadi pada baris 2. Untuk menyelesaikan kesalahan, kompiler akan mencari metode seperti itu dalam lingkup yang memiliki kata kunci implisit dan menggunakan String sebagai argumen dan mengembalikan sebuah Int .
begitu
Konversi penerima secara implisit : Kami umumnya dengan properti objek panggilan penerima, misalnya. metode atau variabel. Jadi, untuk memanggil properti apa pun oleh penerima, properti harus menjadi anggota kelas / objek penerima itu.
Di sini mahadi.haveTv akan menghasilkan kesalahan. Karena scala compiler pertama akan mencari haveTv properti untuk Mahadi penerima. Itu tidak akan menemukan. Kedua akan mencari metode dalam lingkup yang memiliki kata kunci implisit yang mengambil objek Mahadi sebagai argumen dan mengembalikan objek Johnny . Tetapi tidak ada di sini. Jadi itu akan membuat kesalahan . Tapi berikut ini tidak apa-apa.
Injeksi parameter secara implisit : Jika kita memanggil metode dan tidak memberikan nilai parameternya, itu akan menyebabkan kesalahan. Scala compiler berfungsi seperti ini - pertama akan mencoba memberikan nilai, tetapi tidak akan mendapatkan nilai langsung untuk parameter.
Kedua, jika parameter memiliki kata kunci implisit, ia akan mencari val dalam lingkup yang memiliki jenis nilai yang sama. Jika tidak mendapatkannya akan menyebabkan kesalahan.
Untuk mencari masalah ini kompiler akan mencari val implisit yang memiliki tipe Int karena parameter a memiliki kata kunci implisit .
Contoh lain:
kita juga bisa menulis seperti-
Karena l memiliki parameter implisit dan dalam lingkup tubuh metode x , ada variabel lokal implisit ( parameter adalah variabel lokal ) a yang merupakan parameter x , jadi dalam tubuh metode x nilai argumen implisit metode-tanda tangan l adalah diajukan oleh variabel (parameter) lokal implisit metode x secara
a
implisit .Begitu
akan berada di kompiler seperti ini
Contoh lain:
itu akan menyebabkan kesalahan, karena c dalam x {x => c} perlu secara eksplisit melewati nilai dalam argumen atau val implisit dalam lingkup .
Jadi kita dapat membuat parameter fungsi literal tersirat secara eksplisit ketika kita memanggil metode x
Ini telah digunakan dalam metode aksi Play-Framework
jika Anda tidak menyebutkan parameter permintaan sebagai implisit secara eksplisit maka Anda harus telah ditulis-
sumber
Juga, dalam kasus di atas harus ada
only one
fungsi implisit yang tipenyadouble => Int
. Jika tidak, kompiler menjadi bingung dan tidak dapat dikompilasi dengan benar.sumber
Contoh yang sangat mendasar dari Implicits in scala.
Parameter implisit :
Catatan: Di sini
multiplier
secara implisit akan diteruskan ke fungsimultiply
. Parameter yang hilang untuk pemanggilan fungsi dilihat berdasarkan jenis dalam lingkup saat ini yang berarti bahwa kode tidak akan dikompilasi jika tidak ada variabel implisit dari tipe Int dalam ruang lingkup.Konversi tersirat :
Catatan: Ketika kita memanggil
multiply
fungsi yang melewati nilai ganda, kompiler akan mencoba menemukan fungsi implisit konversi dalam lingkup saat ini, yang dikonversiInt
keDouble
(Sebagai fungsimultiply
menerimaInt
parameter). Jika tidak adaconvert
fungsi implisit maka kompiler tidak akan mengkompilasi kode.sumber
Saya memiliki pertanyaan yang sama persis dengan yang Anda miliki dan saya pikir saya harus membagikan bagaimana saya mulai memahaminya dengan beberapa contoh yang sangat sederhana (perhatikan bahwa itu hanya mencakup kasus penggunaan umum).
Ada dua kasus penggunaan umum dalam penggunaan Scala
implicit
.Contohnya adalah sebagai berikut
Menggunakannya pada variabel . Seperti yang Anda lihat, jika
implicit
kata kunci digunakan dalam daftar parameter terakhir, maka variabel terdekat akan digunakan.Menggunakannya pada suatu fungsi . Seperti yang Anda lihat, jika
implicit
digunakan pada fungsi, maka metode konversi tipe terdekat akan digunakan.Semoga ini bisa membantu.
sumber