Bagaimana cara '20 detik 'bekerja di Scala?

130

Bagaimana cara kompilasi berikut:

import scala.concurrent.duration._

val time = 20 seconds

Apa yang sebenarnya terjadi di sini?

ripper234
sumber

Jawaban:

171

Ada beberapa hal yang terjadi.

Pertama, Scala memungkinkan titik dan paren dihilangkan dari banyak pemanggilan metode, jadi 20 secondssama dengan 20.seconds()*.

Kedua, "konversi implisit" diterapkan. Karena 20merupakan Intdan Inttidak memiliki secondsmetode, pencarian compiler untuk konversi implisit yang mengambil Intdan mengembalikan sesuatu yang memang memiliki sebuah secondsmetode, dengan pencarian dibatasi oleh ruang lingkup panggilan metode Anda.

Anda telah mengimpor DurationInt ke dalam cakupan Anda. Karena DurationIntkelas implisit dengan Intparameter, konstruktornya mendefinisikan Int => DurationIntkonversi implisit . DurationIntmemiliki secondsmetode, sehingga memenuhi semua kriteria pencarian. Oleh karena itu, kompiler menulis ulang panggilan Anda sebagai new DurationInt(20).seconds**.

* Maksud saya ini secara longgar. 20.seconds()sebenarnya tidak valid karena secondsmetode tidak memiliki daftar parameter dan oleh karena itu parens harus dihilangkan pada panggilan metode.

** Sebenarnya, ini tidak sepenuhnya benar karena DurationIntmerupakan kelas nilai, jadi kompiler akan menghindari membungkus integer jika memungkinkan.

Aaron Novstrup
sumber
83
Setiap teknologi yang cukup maju tidak dapat dibedakan dari sihir.
ripper234
4
Untungnya sebagian besar IDE mampu membedakannya! Konversi tersirat cukup banyak digunakan di Scala. Jika Anda hanya membaca file teks, itu bisa membingungkan ("dari mana metode itu berasal") tetapi dengan dukungan alat yang tepat Anda harus dapat menemukan jalan sekitar Anda, di mana Scala dapat menjadi bermakna dan indah secara ringkas. (mis., 20 detik jauh lebih mudah dibaca daripada new DurationInt(20).seconds()selama Anda tahu bagaimana melakukannya)
William Billingsley
1
Jika Anda menemukan diri Anda menggunakan implisit, selalu tanyakan pada diri sendiri apakah ada cara untuk mencapai hal yang sama tanpa bantuan mereka. twitter.github.com/effectivescala/#Types and Generics-Implicits
oluies
4
Sebenarnya secondsmetode ini didefinisikan tanpa parens, jadi memanggilnya dengan parens adalah kesalahan.
Frank S. Thomas
1
@ Frank Itu poin yang bagus. Saya tidak bermaksud menyarankan agar Anda dapat menulis 20.seconds()dalam Scala, hanya saja kompiler menerjemahkan panggilan dengan cara itu. Layak untuk menunjukkan bahwa Scala mengharuskan Anda untuk menghilangkan parens jika metode yang sesuai tidak memiliki daftar parameter, seperti dalam kasus ini.
Aaron Novstrup
7

"Sihir" yang terjadi di sana disebut "konversi implisit". Anda mengimpor konversi implisit, dan beberapa di antaranya menangani konversi antara Int (dan Double) ke Durasi. Itulah yang sedang Anda hadapi.

Bruno Reis
sumber
1
Adakah ide mengapa mengimpor import scala.concurrent.duration._diselesaikan 20 secondstetapi sebenarnya mengimpor DurationConversionsTrait tidak? EDIT : Baru menyadari apa yang sebenarnya mereka impor DurationInt. Saya menduga ini karena Anda tidak dapat mengimpor Trait yang sebenarnya? Hanya implementasi sifat yang konkret?
franklin