Teka-teki Kotlin, Vol. 2: kumpulan teka-teki baru



Bisakah Anda memprediksi bagaimana kode Kotlin akan berlaku? Apakah akan mengkompilasi apa yang akan dihasilkan dan mengapa?

Tidak peduli sebagus apa pun bahasa pemrogramannya, ia dapat membuangnya sehingga hanya tersisa untuk menggaruk bagian belakang kepalanya. Tidak terkecuali Kotlin - Kotlin juga mengandung teka-teki, bahkan ketika kode yang sangat pendek memiliki perilaku yang tidak terduga.

Kembali pada tahun 2017, kami menerbitkan di HabrƩ sebuah pilihan teka-teki semacam itu dari antonkeks Anton Keks . Dan kemudian dia tampil bersama kami di Mobius dengan pilihan kedua, dan kami sekarang juga menerjemahkannya untuk Habr ke tampilan teks, menyembunyikan jawaban yang benar di bawah spoiler.

Kami juga melampirkan rekaman video pidato, jika ada sesuatu yang tidak dapat dipahami dalam teks, Anda juga dapat menghubunginya.


Bagian pertama dari teka-teki ini ditujukan untuk mereka yang tidak terlalu mengenal Kotlin; bagian kedua adalah untuk pengembang hardcore Kotlin. Kami akan memulai semuanya di Kotlin 1.3, bahkan dengan mode progresif diaktifkan. Kode sumber kusut ada di GitHub . Siapa pun yang datang dengan ide-ide baru, kirim permintaan tarik.

Pazzler nomor 1


fun hello(): Boolean { println(print(″Hello″) == print(″World″) == return false) } hello() 

Sebelum kita adalah fungsi halo sederhana, ia menjalankan beberapa cetak. Dan kami meluncurkan fungsi ini sendiri. Pertanyaan overclocking sederhana: apa yang harus dicetak?

a) HelloWorld
b) HelloWorldfalse
c) HelloWorldtrue
d) Tidak dikompilasi

Jawaban yang benar


Opsi pertama benar. Perbandingan dipicu setelah kedua cetakan sudah mulai, tidak bisa mulai lebih awal. Mengapa kode seperti itu dikompilasi? Fungsi apa pun selain mengembalikan Tidak ada yang mengembalikan sesuatu. Karena segala sesuatu di Kotlin adalah ekspresi, bahkan kembali juga merupakan ekspresi. Jenis pengembalian adalah Tidak, itu digunakan untuk jenis apa pun, sehingga Anda dapat membandingkan seperti ini. Dan mencetak pengembalian Unit, sehingga Unit dapat dibandingkan dengan Tidak ada berapa kali, dan semuanya berfungsi dengan baik.

Pazzler nomor 2


 fun printInt(n: Int) { println(n) } printInt(-2_147_483_648.inc()) 

Jangan sampai Anda menebak: angka menakutkan adalah integer bertanda 32-bit sekecil mungkin.

Semuanya terlihat sederhana di sini. Kotlin memiliki fungsi ekstensi yang hebat seperti .inc () untuk menambah. Kita bisa menyebutnya di Int, dan kita bisa mencetak hasilnya. Apa yang akan terjadi

a) -2147483647
b) -2147483649
c) 2147483647
d) Tidak satu pun di atas

Luncurkan!


Seperti yang dapat Anda lihat dari pesan kesalahan, inilah masalah dengan Long. Tapi kenapa lama?

Fungsi ekstensi memiliki prioritas, dan kompiler pertama kali menjalankan inc (), dan kemudian operator minus. Jika inc () dihapus, maka itu akan menjadi Int, dan semuanya akan berfungsi. Tapi inc (), mulai lebih dulu, mengubah 2_147_483_648 menjadi Long, karena angka ini tanpa minus tidak lagi berlaku Int. Ternyata Long, dan baru kemudian minus disebut. Semua ini tidak lagi dapat diteruskan ke fungsi printInt (), karena memerlukan Int.

Jika kita mengubah panggilan printInt ke cetakan biasa, yang dapat menerima Long, maka opsi kedua akan benar.



Kami melihat bahwa ini sebenarnya Panjang. Waspadalah terhadap hal ini: tidak semua potongan puzzle dapat dijalankan dalam kode nyata, tetapi yang ini bisa.

Pazzler nomor 3


 var x: UInt = 0u println(x--.toInt()) println(--x) 

Di Kotlin 1.3 datang fitur-fitur hebat baru. Selain versi final corutin, kami
sekarang akhirnya memiliki nomor yang tidak ditandatangani. Ini perlu, terutama jika Anda menulis semacam kode jaringan.

Sekarang untuk literal bahkan ada huruf u khusus, kita dapat mendefinisikan konstanta, kita dapat, seperti dalam contoh, pengurangan x dan dikonversi ke Int. Saya mengingatkan Anda bahwa Int akrab dengan kami.

Apa yang akan terjadi

a) -1 4294967294
b) 0 4294967294
c) 0 -2
d) Tidak dikompilasi

4294967294 adalah jumlah maksimum 32-bit yang dapat diperoleh.

Luncurkan!


Opsi yang benar b.

Di sini, seperti pada versi sebelumnya: pertama, toInt () dipanggil pada x, dan baru setelah itu decrement. Hasil decrement unsigned ditampilkan, dan ini adalah maksimum dari unsignedInt.

Yang paling menarik adalah jika Anda menulis seperti ini, kode tidak akan dikompilasi:

 println(x--.toInt()) println(--x.toInt()) 

Dan bagi saya sangat aneh bahwa baris pertama bekerja, dan yang kedua - tidak, ini tidak masuk akal.

Dan dalam versi pra-rilis, opsi yang benar adalah C, yang dilakukan dengan sangat baik di JetBrains yang memperbaiki bug sebelum rilis versi final.

Pazzler nomor 4


 val cells = arrayOf(arrayOf(1, 1, 1), arrayOf(0, 1, 1), arrayOf(1, 0, 1)) var neighbors = cells[0][0] + cells[0][1] + cells[0][2] + cells[1][0] + cells[1][2] + cells[2][0] + cells[2][1] + cells[2][2] print(neighbors) 

Kami mengalami kasus ini dalam kode nyata. Kami di Codeborne melakukan Coding Dojo, menerapkannya bersama di Kotlin Game of Life . Seperti yang Anda lihat, sangat tidak nyaman untuk bekerja dengan array multi-level di Kotlin.

Dalam Game of Life, bagian penting dari algoritma adalah menentukan jumlah tetangga untuk sebuah sel. Semua anak kecil di sekitarnya adalah tetangga, dan itu tergantung pada apakah sel hidup atau mati. Dalam kode ini, Anda dapat menghitung dan menganggap apa yang terjadi.

a) 6
b) 3
c) 2
d) Tidak dikompilasi

Ayo lihat


Jawaban yang benar adalah 3.

Faktanya adalah nilai tambah dari baris pertama dipindahkan ke bawah, dan Kotlin berpikir ini adalah unaryPlus (). Akibatnya, hanya tiga sel pertama yang dijumlahkan. Jika kita ingin menulis kode ini dalam beberapa baris, kita perlu memindahkan plus ke atas.

Ini adalah satu lagi dari "teka-teki buruk." Ingat, di Kotlin Anda tidak perlu mentransfer pernyataan ke baris baru, jika tidak, pernyataan itu mungkin dianggap tidak wajar.



Saya belum melihat situasi di mana unaryPlus diperlukan dalam kode nyata kecuali DSL. Ini adalah topik yang sangat aneh.

Ini adalah harga yang kami bayar jika tidak ada titik koma. Jika ya, akan menjadi jelas kapan satu ekspresi berakhir dan yang lain dimulai. Dan tanpa mereka, kompiler harus membuat keputusan. Umpan baris untuk kompiler sangat sering berarti bahwa masuk akal untuk mencoba memeriksa saluran secara terpisah.

Tetapi ada satu bahasa JavaScript yang sangat keren di mana Anda juga tidak bisa menulis titik koma, dan kode ini akan tetap berfungsi dengan benar.

Pazzler nomor 5


 val x: Int? = 2 val y: Int = 3 val sum = x?:0 + y println(sum) 

Teka-teki ini ditampilkan oleh pembicara KotlinConf Thomas Nild.

Kotlin memiliki fitur tipe nullable yang bagus. Kami memiliki x nullable, dan kami dapat mengubahnya, jika ternyata nol, melalui operator Elvis ke beberapa nilai normal.

Apa yang akan terjadi

a) 3
b) 5
c) 2
d) 0

Luncurkan!


Masalahnya lagi dalam urutan atau prioritas operator. Jika kami memformat ulang ini, maka format resmi akan melakukan ini:

 val sum = x ?: 0+y 

Format sudah menunjukkan bahwa 0 + y mulai lebih dulu, dan baru kemudian x?:. Oleh karena itu, tentu saja, 2 tetap, karena X adalah dua, itu bukan nol.

Pazzler nomor 6


 data class Recipe (var name: String? = null, var hops: List<Hops> = emptyList() ) data class Hops(var kind: String? = null, var atMinute: Int = 0, var grams: Int = 0) fun beer(build: Recipe.() -> Unit) = Recipe().apply(build) fun Recipe.hops(build: Hops.() -> Unit) { hops += Hops().apply(build) } val recipe = beer { name = ″Simple IPA″ hops { name = ″Cascade″ grams = 100 atMinute = 15 } } 

Ketika mereka memanggil saya di sini, mereka berjanji akan membuat bir. Saya akan mencarinya malam ini, saya belum melihatnya. Kotlin memiliki topik hebat - pembangun. Dengan empat baris kode, kami menulis DSL kami dan kemudian membuatnya melalui pembangun.

Kami membuat, pertama, IPA, tambahkan hop yang disebut Cascade, 100 gram pada menit ke-15, dan kemudian cetak resep ini. Apa yang kita lakukan

a) Resep (nama = IPA Sederhana, hop = [Hop (nama = Cascade, atMinute = 15, gram = 100)])
b) IllegalArgumentException
c) Tidak dikompilasi
d) Tidak satu pun di atas

Luncurkan!


Kami mendapat sesuatu yang mirip dengan kerajinan bir, tetapi tidak ada hop di dalamnya, itu menghilang. Mereka menginginkan IPA, tetapi mendapat Baltik 7.

Di sinilah bentrokan penamaan terjadi. Bidang di Hops sebenarnya disebut jenis, dan dalam nama baris = ″ Cascade ″ kami menggunakan nama, yang di-cache dengan nama resep.

Kita dapat membuat anotasi BeerLang kita sendiri dan mendaftarkannya sebagai bagian dari BeerLang DSL. Sekarang kami mencoba menjalankan kode ini, dan tidak boleh dikompilasi dengan kami.



Sekarang kita diberitahu bahwa pada prinsipnya nama tidak dapat digunakan dari konteks ini. Untuk ini, DSLMarker diperlukan karena kompiler di dalam pembangun tidak memungkinkan kami untuk menggunakan bidang eksternal, jika kami memiliki yang sama di dalamnya sehingga tidak ada bentrokan penamaan. Kode diperbaiki seperti ini, dan kami mendapatkan resep kami.



Pazzler nomor 7



 fun f(x: Boolean) { when (x) { x == true -> println(″$x TRUE″) x == false -> println(″$x FALSE″) } } f(true) f(false) 

Teka-teki ini adalah salah satu karyawan JetBrains. Kotlin memiliki fitur kapan. Ini untuk semua kesempatan, memungkinkan Anda untuk menulis kode keren, sering digunakan bersama dengan kelas disegel untuk desain API.

Dalam hal ini, kami memiliki fungsi f () yang mengambil Boolean dan mencetak sesuatu tergantung pada true dan false.

Apa yang akan terjadi

a) BENAR benar; false false
b) BENAR benar; BENAR salah
c) FALSE sejati; false false
d) Tidak satu pun di atas

Ayo lihat


Kenapa begitu Pertama, kita menghitung ekspresi x == true: misalnya, dalam kasus pertama, itu akan menjadi benar == benar, yang berarti benar. Dan kemudian ada juga perbandingan dengan pola yang kita lewati saat itu.

Dan ketika x disetel ke false, mengevaluasi x == true akan memberi kita false, namun, sampel juga akan salah - jadi contohnya akan cocok dengan sampel.

Ada dua cara untuk memperbaiki kode ini, Pertama adalah menghapus "x ==" dalam kedua kasus:

 fun f(x: Boolean) { when (x) { true -> println(″$x TRUE″) false -> println(″$x FALSE″) } } f(true) f(false) 

Opsi kedua adalah menghapus (x) setelah kapan. Ketika bekerja dengan kondisi apa pun, dan kemudian tidak akan cocok dengan sampel.

 fun f(x: Boolean) { when { x == true -> println(″$x TRUE″) x == false -> println(″$x FALSE″) } } f(true) f(false) 


Pazzler nomor 8


 abstract class NullSafeLang { abstract val name: String val logo = name[0].toUpperCase() } class Kotlin : NullSafeLang() { override val name = ″Kotlin″ } print(Kotlin().logo) 

Kotlin dipasarkan sebagai bahasa ā€œnull safeā€. Bayangkan bahwa kita memiliki kelas abstrak, memiliki beberapa nama, serta properti yang mengembalikan logo bahasa ini: huruf pertama dari nama, untuk berjaga-jaga, huruf kapital (tiba-tiba lupa membuat modal awal).

Karena bahasanya tidak aman, kami akan mengganti nama dan mungkin harus mendapatkan logo yang benar, yaitu satu huruf. Apa yang sebenarnya kita dapatkan?

a) K
b) NullPointerException
c) IllegalStateException
d) Tidak dikompilasi

Luncurkan!


Kami mendapat NullPointerException, yang seharusnya tidak kami terima. Masalahnya adalah konstruktor dari superclass disebut pertama, kode mencoba menginisialisasi logo properti dan mengambil nama char dari nol, dan pada saat ini nama adalah nol, sehingga terjadi NullPointerException.

Cara terbaik untuk memperbaikinya adalah dengan melakukan ini:

 class Kotlin : NullSafeLang() { override val name get() = ″Kotlin″ } 

Jika kita menjalankan kode seperti itu, kita mendapat "K". Sekarang kelas dasar akan memanggil konstruktor dari kelas dasar, itu sebenarnya akan memanggil nama pengambil dan mendapatkan Kotlin.

Properti adalah fitur hebat di Kotlin, tetapi Anda harus sangat berhati-hati ketika melakukan override properti, karena sangat mudah untuk melupakan, membuat kesalahan, atau memastikan hal yang salah.


Pazzler nomor 9


 val result = mutableListOf<() -> Unit>() var i = 0 for (j in 1..3) { i++ result += { print(″$i, $j; ″) } } result.forEach { it() } 

Ada daftar mutable dari beberapa hal menakutkan. Jika itu mengingatkan Anda pada Scala, maka itu tidak sia-sia, karena itu benar-benar terlihat seperti. Ada Daftar lambd, kami mengambil dua counter - I dan j, increment dan kemudian melakukan sesuatu dengan mereka. Apa yang akan terjadi

a) 1 1; 2 2; 3 3
b) 1 3; 2 3; 3 3
c) 3 1; 3 2; 3 3
d) tidak ada di atas

Ayo lari


Kami mendapatkan 3 1; 3 2; 3 3. Ini terjadi karena saya adalah variabel, dan itu akan mempertahankan nilainya sampai akhir fungsi. Dan j dilewatkan oleh nilai.

Jika alih-alih var i = 0 akan ada val i = 0, ini tidak akan berfungsi, tetapi kemudian kita tidak bisa menambah variabel.

Di sini, di Kotlin kami menggunakan penutupan, fitur ini bukan di Jawa. Ini sangat keren, tetapi dapat menggigit kita jika kita tidak segera menggunakan nilai i, tetapi meneruskannya ke lambda, yang dimulai kemudian dan melihat nilai terakhir dari variabel ini. Dan j dilewatkan oleh nilai, karena variabel dalam kondisi loop - mereka sama dengan val, mereka tidak mengubah nilainya lagi.

Dalam JavaScript, jawabannya adalah ā€œ3 3; 3 3; 3 3 ", karena tidak ada yang ditransmisikan oleh nilai.


Pazzler nomor 10


 fun foo(a:Boolean, b: Boolean) = print(″$a, $b″) val a = 1 val b = 2 val c = 3 val d = 4 foo(c < a, b > d) 

Kami memiliki fungsi foo (), mengambil dua Boolean, mencetaknya, semuanya tampak sederhana. Dan kami memiliki banyak angka, masih untuk melihat angka mana yang lebih besar dari yang lain, dan memutuskan opsi mana yang benar.

a) benar, benar
b) salah, salah
c) nol, nol
d) tidak dikompilasi

Kami meluncurkan


Tidak dikompilasi.

Masalahnya adalah bahwa kompiler berpikir ini mirip dengan parameter generik: dengan <a, b>. Meskipun sepertinya "c" bukan kelas, tidak jelas mengapa harus memiliki parameter generik.

Jika kodenya seperti ini, itu akan berfungsi dengan baik:

 foo(c > a, b > d) 

Sepertinya saya ini adalah bug di kompiler. Tetapi ketika saya pergi ke Andrei Breslav dengan teka-teki seperti itu, dia berkata "ini karena parser seperti itu, mereka tidak ingin terlalu lambat." Secara umum, ia selalu menemukan penjelasan mengapa.

Sayangnya, ini benar. Dia mengatakan bahwa mereka tidak akan memperbaikinya, karena pengurai di
Kotlin belum tahu semantik. Parsing terjadi terlebih dahulu, dan kemudian meneruskannya ke komponen kompiler lain. Sayangnya, ini mungkin akan tetap demikian. Jadi jangan menulis dua kurung sudut dan kode apa pun di tengah!

Pazzler nomor 11


 data class Container(val name: String, private val items: List<Int>) : List<Int> by items val (name, items) = Container(″Kotlin″, listOf(1, 2, 3)) println(″Hello $name, $items″) 

Mendelegasikan adalah fitur hebat di Kotlin. Ngomong-ngomong, Andrei Breslav mengatakan bahwa ini adalah fitur yang dengan senang hati akan dia hapus dari bahasa itu, dia tidak lagi menyukainya. Sekarang, mungkin, kita akan mencari tahu alasannya! Dan dia juga mengatakan bahwa benda pendamping itu jelek.

Tetapi kelas data jelas sangat indah. Kami memiliki Container kelas data, dibutuhkan nama dan item untuk dirinya sendiri. Pada saat yang sama, dalam Kontainer, kami menerapkan jenis barang, ini Daftar, dan kami mendelegasikan semua metode untuk item.

Lalu kami menggunakan fitur keren lainnya - destructure. Kami "merusak" elemen nama dan item dari Wadah dan menampilkannya di layar. Segalanya tampak sederhana dan jelas. Apa yang akan terjadi

a) Halo Kotlin, [1, 2, 3]
b) Halo Kotlin, 1
c) Halo 1, 2
d) Halo Kotlin, 2

Kami meluncurkan


Opsi yang paling tidak jelas adalah d. Dia ternyata benar. Ternyata, item hilang begitu saja dari koleksi item, dan bukan dari awal atau dari akhir, tetapi hanya di tengah. Mengapa

Masalah dengan kerusakan adalah karena delegasi, semua koleksi di Kotlin juga
memiliki opsi sendiri untuk melakukan restrukturisasi. Saya dapat menulis val (I, j) = listOf (1, 2), dan memasukkan 1 dan 2 ini ke dalam variabel, yaitu, List telah mengimplementasikan fungsi component1 () dan
component2 ().

Kelas data juga memiliki component1 () dan component2 (). Tetapi karena komponen kedua dalam kasus ini adalah pribadi, komponen yang bersifat publik di Daftar menang, jadi elemen kedua diambil dari Daftar, dan kami tiba di sini 2. Moralnya sangat sederhana: jangan lakukan itu, jangan lakukan itu.

Pazzler nomor 12


Teka-teki berikutnya sangat menakutkan. Ini adalah orang yang patuh yang entah bagaimana terhubung dengan Kotlin, jadi dia tahu apa yang dia tulis.

 fun <T> Any?.asGeneric() = this as? T 42.asGeneric<Nothing>()!!!! val a = if (true) 87 println(a) 

Kami memiliki fungsi ekstensi pada nullable Any, yaitu, dapat diterapkan sama sekali untuk apa pun. Ini adalah fitur yang sangat berguna. Jika belum ada di proyek Anda, ada baiknya ditambahkan, karena itu dapat memasukkan semua yang Anda inginkan ke dalam apa pun. Lalu kami mengambil 42 dan membuangnya ke Nothing.

Nah, jika kita ingin memastikan bahwa kita telah melakukan sesuatu yang penting, kita bisa melakukannya !!! tulis !!!!, kompiler Kotlin memungkinkan Anda melakukan ini: jika Anda kehilangan dua tanda seru, tulis setidaknya dua puluh enam.

Lalu kita lakukan jika (benar), dan kemudian saya sendiri tidak mengerti apa-apa ... Ayo segera pilih apa yang terjadi.

a) 87
b) Kotlin.Unit
c) ClassCastException
d) Tidak dikompilasi

Menonton


Sangat sulit untuk memberikan penjelasan yang logis. Kemungkinan besar, Unit di sini disebabkan oleh fakta bahwa tidak ada lagi yang mendorong di sana. Ini adalah kode yang tidak valid, tetapi berfungsi karena kami tidak menggunakan apa pun. Kami telah mengunggah sesuatu ke Nothing, dan ini adalah tipe khusus yang memberi tahu kompiler bahwa instance dari tipe ini seharusnya tidak pernah muncul. Kompiler tahu bahwa jika ada kemungkinan Nothing, yang tidak mungkin menurut definisi, maka Anda tidak dapat memeriksa lebih lanjut, ini adalah situasi yang tidak mungkin.

Kemungkinan besar, ini adalah bug di kompiler, tim JetBrains bahkan mengatakan bahwa mungkin bug ini akan diperbaiki suatu hari nanti, ini bukan prioritas utama. Kuncinya adalah bahwa kita menipu kompiler di sini karena pemain ini. Jika Anda menghapus baris 42.asGeneric <Nothing> () !!! dan berhenti curang, kode akan berhenti mengkompilasi. Dan jika kita pergi, kompiler menjadi gila, berpikir bahwa ini adalah ekspresi yang tidak mungkin, dan hal-hal apa pun yang masuk ke sana.

Saya mengerti itu. Mungkin suatu hari nanti seseorang akan menjelaskannya dengan lebih baik.


Pazzler nomor 13


Kami memiliki fitur yang sangat menarik. Anda dapat menggunakan injeksi dependensi, atau Anda bisa melakukannya tanpa itu, membuat singletones melalui objek dan menjalankan program Anda keren. Mengapa Anda membutuhkan Koin, Belati atau sesuatu? Namun, pengujian akan sulit.

 open class A(val x: Any?) { override fun toString() = javaClass.simpleName } object B : A(C) object C : A(B) println(Bx) println(Cx) 

Kami memiliki kelas A terbuka untuk warisan, dibutuhkan sesuatu di dalam dirinya sendiri, kami membuat dua objek'a, tunggal, B dan C, keduanya diwarisi dari A dan saling melewati di sana. Artinya, siklus yang sangat baik terbentuk. Lalu kami mencetak apa yang didapat B dan C.

a) nol; null
b) C; null
c) ExceptionInInitializerError
d) Tidak dikompilasi

Kami meluncurkan


Opsi yang benar adalah C; null

Orang akan berpikir bahwa ketika objek pertama diinisialisasi, yang kedua belum ada di sana. Tetapi, ketika kita menyimpulkan ini, C tidak memiliki B. Artinya, urutan terbalik diperoleh: untuk beberapa alasan, kompiler memutuskan untuk menginisialisasi C pertama, dan kemudian ia menginisialisasi B bersama-sama dengan C. Itu terlihat tidak logis, itu akan menjadi logis, sebaliknya akan logis, sebaliknya, nol ; B.

Tetapi kompiler mencoba melakukan sesuatu, itu tidak berhasil, ia meninggalkan nol di sana dan memutuskan untuk tidak memberikan apa pun kepada kami. Bisa jadi itu juga

Jika ada? pada tipe parameter, hapus ?, maka tidak akan berfungsi.



Kita dapat mengatakan baik kepada kompiler bahwa ketika null diselesaikan, dia mencoba, tetapi gagal, tetapi apa? tidak, dia melempar kami pengecualian bahwa tidak mungkin untuk membuat siklus.

Pazzler ā„–14


Versi 1.3 merilis coroutine baru yang hebat di Kotlin. Sudah lama saya berpikir bagaimana membuat teka-teki tentang corutin, sehingga seseorang bisa memahaminya. Saya pikir bagi sebagian orang kode dengan coroutine adalah kusut.

Di 1.3, beberapa nama fungsi berubah yang berada di 1.2 di API eksperimental. Misalnya, buildSequence () diubah namanya menjadi hanya urutan (). Artinya, kita dapat membuat urutan yang sangat baik dengan fungsi hasil, loop tak terbatas, dan kemudian kita bisa mencoba untuk mendapatkan sesuatu dari urutan ini.

 package coroutines.yieldNoOne val x = sequence { var n = 0 while (true) yield(n++) } println(x.take(3)) 

Mereka mengatakan dengan coroutine bahwa semua primitif keren yang ada dalam bahasa lain, seperti hasil, dapat dilakukan sebagai fungsi perpustakaan, karena hasil adalah fungsi penangguhan yang dapat terganggu.

Apa yang akan terjadi

a) [1, 2, 3]
b) [0, 1, 2]
c) Loop tak terbatas
d) Tidak satu pun di atas

Luncurkan!


Opsi yang benar adalah yang terakhir.

Urutan adalah alat malas, dan ketika kita berpegang teguh pada itu, itu juga malas. Tetapi jika Anda menambahkan toList, maka itu akan benar-benar dicetak [0, 1, 2].

Jawaban yang benar tidak terkait dengan coroutine sama sekali. Coroutine benar-benar berfungsi, mudah digunakan. Untuk fungsi urutan dan hasil, Anda bahkan tidak perlu menghubungkan pustaka dengan coroutine, semuanya sudah ada di pustaka standar.

Pazzler ā„–15


Teka-teki ini juga ditundukkan oleh pengembang dari JetBrains. Ada kode seperti itu:

 val whatAmI = {->}.fun Function<*>.(){}() println(whatAmI) 

Ketika saya melihatnya pertama kali, selama KotlinConf, saya tidak bisa tidur, saya mencoba memahami apa itu. Kode samar seperti itu dapat ditulis dalam Kotlin, jadi jika seseorang berpikir Scalaz menakutkan, maka di Kotlin juga mungkin.

Mari tebak:

a) Kotlin.Unit
b) Kotlin. Tidak ada
c) Tidak dikompilasi
d) Tidak satu pun di atas

Ayo lari


Kami mendapat Unit yang datang entah dari mana.

Mengapa Pertama kita menetapkan variabel lambda: {->} - ini adalah kode yang valid, Anda dapat menulis lambda kosong. Tidak memiliki parameter, tidak mengembalikan apa pun. Dengan demikian, ia mengembalikan Unit.

Kami menetapkan lambda ke variabel dan segera menulis ekstensi ke lambda ini, dan kemudian menjalankannya. Bahkan, itu hanya akan memesan Kotlin.Unit.

Kemudian pada lambda ini Anda dapat menulis fungsi ekstensi:

 .fun Function<*>.(){} 

Ini dideklarasikan pada tipe Function <*>, dan apa yang kita miliki di atas juga cocok untuk itu. Sebenarnya itu adalah Function <Unit>, tapi saya tidak menulis Unit yang tidak jelas. Apakah Anda tahu cara kerja tanda bintang di Kotlin? , Java. , .

, Unit {}, , void-. , , . -, — .

. , Kotlin — . iOS- , , Kotlin !
Mobius, : Mobius 22-23 . Kotlin — Ā«Coroutining Android AppsĀ» . ( Android, iOS), — , 1 .

: , — 6 .

Source: https://habr.com/ru/post/id440974/


All Articles