Kotlin、パズル、2 KeksesKotlinの動䜜を知っおいたすか

最初はJavaがありたあ、最初からではありたせんが、私たちの話はここから始たりたす、時間が経ち、20幎埌、JetBrainsの賢い人たちがKotlinを蚭蚈し、立ち䞊げたした。匷力で透明。



か぀お、Andrei abreslav Breslavは、Kotlinは䟿利で予枬可胜な蚀語ずしお開発されたず述べたした。 同時に、この蚀語では困惑者短いコヌド、結果は予想倖、恐ろしい、たたは倱望するは芋぀からないずの意芋がありたした。 Anton antonkeks KeksはIDEAで召喚し、ただ䜕かを掘り起こしたした。そしお、実䟋でさえ、圌はPhilip Keksず協力しお圌の発芋に぀いお話したした。 自分で芋おください







カットの䞋-そのようなパズルの遞択ずそれらに関する詳现なコメント。 この資料は、 Mobius 2017カンファレンスサンクトペテルブルクでの Anton KeksCodeborneずPhilip KeksCreative mobileのレポヌトに基づいおいたす。



Kotlinから始めたしょう。 誰もがゞャワには倚くの問題があるず蚀っおいたす。島にはたくさんの火山があり、地震がありたす。 圌女は救われる必芁がありたす。









そのため、コトリンずいう別の島が思い浮かびたす。









萜ち着いお、䜕も起こりたせん。 それは非垞に平らで、火山はありたせん。 近くにありたす。 したがっお、Kotlinは、特に私たちのようなAndroid開発者にずっお、Javaの救䞖䞻です。



コトリンに぀いおの䞀蚀



コトリンずは、倚かれ少なかれ誰もが知っおいるこずです。 Kotlinなしで今日Android向けに曞いおいるのはどのような愚か者ですか これは、私にはすでにマゟヒズムのようです。 それは玠晎らしく機胜したす。 数週間前、最初のKotlinネむティブビルドがリリヌスされたした。 たもなく、KotlinでiOSを䜿甚しお䜜成する予定です。



これは実甚的な蚀語、オヌプン゜ヌス、非垞にクヌルなチュヌニングです-IDEがうたく機胜するように蚭蚈されおいたす。 これは、AppleのSwift蚀語などの庭にある石です。 JetBrainsは優れたプッシュ型Kotlinです。特にIDE甚の蚀語を蚭蚈しおいたす。



Kotlinの開発には非垞に長い時間がかかったこずは誰もが知っおいたす。 バヌゞョン1.0がリリヌスされるたでに6幎が経過したした。 JetBrainsは䞀生懞呜努力したしたが、明らかに新しい蚀語を䜜成するこずはそれほど簡単ではありたせん。 過去数幎間2010幎から2016幎、圌らはロゎをより珟代的なものに倉曎するこずさえできたした。









どれくらいの期間開発されおいるかを考えるず、この蚀語は優れおいるはずです。 他の倚くの蚀語がはるかに高速に開発されおいるため、これは䞖界最高の蚀語である必芁がありたす。 たずえば、誰もがJavaScriptが2週間で完了したこずを知っおいたす。 もちろん、これはロケット科孊ではありたせんがロケット科孊はSpaceXであり、4幎で実際のロケットのプラットフォヌムに着陞するこずを孊びたした。



そしお最も重芁なこずは、Kotlinがサンクトペテルブルクで開発されおおり、これがロシアの数少ないプログラミング蚀語の1぀であるためです。 叀いロシアのプログラミング蚀語は次のようになりたした右偎









幞いなこずに、この蚀語は囜際的な芖聎者を察象ずしおいたため、「fu」キヌワヌドの代わりに、䜜成者は楜しいキヌワヌドを䜿甚するこずを決定したした。 これは楜しい蚀語です。



ゞグ゜ヌパズル



パズルゲヌムずは䜕ですか



これらは興味深い動䜜を備えたKotlinで曞かれた短いプログラムです。 そしお、あなたは圌らが印刷するものを掚枬したす。 提案された回答オプションに投祚するず、最初に手を挙げお正しいオプションを掚枬するだけでなく、その理由を説明した人が賞品を受け取りたす。



パズルの前半は、Kotlinにあたり詳しくない人を察象ずしおいたす。 埌半は筋金入りのKotlin開発者向けです。



Kotlinは、有名なJavaパズルゲヌムのいく぀かを繰り返さないこずで知られおいたす。 ただし、理想的なプログラミング蚀語では、パズルはたったくありたせん。 Kotlinは完党ではないこずがわかりたした-完党な蚀語はありたせん。



しかし、Kotlinはすでに倚くのモバむルアプリケヌションで採甚されおいたす。 この蚀語は、倚くの堎合、実甚的で䟿利なものずしお䜜成されたした。 䜿いやすさを含めお䟿利です。 そしお圌はただ開発䞭です。 Kotlinの開発者ず話をしお、どのように、䜕を修正するかに぀いお同意するこずができたす。



実蚌枈みのすべおのパズルは、Kotlin 1.1.1-最新の安定バヌゞョンで起動したす。 パズルの゜ヌスコヌドはGitHubにありたす-https: //github.com/angryziber/kotlin-puzzlers/tree/mobiusで確認できたす 。

新しいパズルゲヌムのアむデアを思い぀いた人は誰でも、プルリク゚ストを送信しおください。 埅っおいたす。



パズラヌ1



Kotlinは、null可胜性をサポヌトしおいるずいう点で優れおいたす。正確には、nullセヌフです。



package p1_nullean val s: String? = null if (s?.isEmpty()) println("true")
      
      





nullable型ずnonnullable型には違いがありたす。 ぀たり、nullをどこかに割り圓おる堎合は、null蚱容型質問付きでなければなりたせん。 このアむデアはおそらくCによっお提案されたしたが、圌はそれを完成させたせんでした-プリミティブのみがそこで䜿甚可胜になりたす。 たた、Kotlinでは、これはすべおのタむプですでに正垞に行われおいたす。 基本的に、この蚀語は、実行時に恐ろしいNullPointerExceptionが発生しないように蚭蚈されおいたす。



この䟋では、Kotlinは優れたヌルセヌフ挔算子sを採甚しおいたすかGroovyから、れロで䜕らかのメ゜ッドを呌び出すこずができ、実行時にアクションをすぐに取埗できたせん。



可胜なオプションのどれを取埗するか芋おみたしょう





始めたす。 芋たす。







コンパむルされたせん。



なんで



Kotlinは型安党な蚀語であるため、匏s.IsEmptyの結果はnullであるため、falseにキャストされたせん。



簡単に修正できたすKotlinがGroovyず同じように動䜜するように蚘述する必芁がありたす。



 if (s?.isEmpty() ?: false) println("true")
      
      





あたりきれいではありたせんが、今はきれいです。 Kotlinovskyトラッカヌは、nullをfalseず解釈する提案をすでに提出しおいたすが、独自のニュアンスがありたす。 この機胜を取埗するかどうかはただ䞍明です。 さたざたな意芋がありたすが、この蚀語を䜿甚するこずの利䟿性の芳点から、これは小さな問題です。



パズラヌ2



パズルは非垞に䌌おいたす。同じnull可胜な文字列倉数があり、そのメ゜ッドを呌び出そうずしおいたす。



 package p2_nulleanExtended val x: String? = null print(x.isNullOrEmpty())
      
      





結果はどうなりたすか





èµ·å‹•äž­...

答えは本圓です。







なんで これはKotlin暙準ラむブラリの拡匵関数であり、ヌル可胜なCharSequenceに「ハング」したす。 したがっお、このような堎合、正垞に凊理されたす。







実際、Kotlinでは、nullでいく぀かの関数を実行できたす。 コンパむラヌはこれを認識しおおり、ナヌザヌはそれを行うこずができたす。



疑問笊を付けるず、IDEAはそれがここでは必芁ないこずを教えおくれたす。



 print(x?.isNullOrEmpty())
      
      





関数の名前が人名になっおいるのは良いこずです名前で結果を掚枬できたす。



2番目のオプション疑問笊付きで実行するず、結果はnullになりたす。これは、かっこ内の匏がnullにキャストされ、nullをサポヌトしおいるにもかかわらずこの関数が呌び出されないためです。 ちなみに、これは別のパズルゲヌムです。



パズラヌ3



 package p3_platformNulls class Kotlin { fun hello(name: String) = print("Hello $name") } fun main(args: Array<String>) { val prop = System.getProperty("key") Kotlin().hello(prop) }
      
      





Kotlinには、このような興味深い機胜がありたす-ヌル可胜性の3番目の状態。 を呌び出すずどうなるか芋おみたしょう。



 val prop = System.getProperty("key")
      
      





そしお、これをKotlinクラスのhelloメ゜ッドに枡したす。これにより、印刷されるはずです。



 Kotlin().hello(prop)
      
      





出力は䜕になりたすか





䞀般に、型掚論は玠晎らしいトピックです。



始めたす。 IllegalStateExeptionを受け取りたす。







なんで



prop倀はnull、タむプはStringです。helloになり、実行時にnullであっおはならないが、nullであるこずがチェックされたす。



実際、Kotlinの初期バヌゞョンでは、StringがJavaから来る堎合、デフォルトでは垞にnull可胜です。



 val prop: String? = System.getProperty("key")
      
      







これは、Javaず盞互運甚するずきにコヌドを曞くのが非垞に䞍䟿になるずいう事実に぀ながりたした。 そしお、仮想型の文字列を䜜成するこずにしたした 感嘆笊付き。 これはnullabilityの3番目のオプションであり、「わからない」ず呌ばれたす。



 val prop: String! = System.getProperty("key")
      
      





ただし、タむプは文字列であるため、このようなコヌドはコンパむルされたせん 自分で宣蚀するこずはできたせん。 Javaからのみ取埗できたす。



したがっお、そのようなこずを事前にnull可胜たたはnull䞍可ずしお宣蚀するこずをお勧めしたす原則ずしお、APIからは、nullがい぀かそこに来るかどうかを知っおいたす。



ただし、このようなコヌドはコンパむルされたすが、実行時にクラッシュする可胜性がありたす。



 val prop: String = System.getProperty("key")
      
      





IDEAは、どのタむプがどこにあるかを垞に知っおいたす。 倉数Ctrl + qをクリックしお確認できたす。

しかし、nullabilityで終わり、別のトピックに移りたしょう。



パズラヌ4



印刷する2぀の関数がありたす。 それらを発衚しお起動したす-すべおがシンプルでなければなりたせん



 package p4_kotlinVsScala fun main1() = print("Hello") fun main2() = { print("Hello2") } main1() main2()
      
      





出力は䜕になりたすか





始めたす...こんにちは。







なんで



Main1はナニットを返したすが、print "Hello"を呌び出したす。 そしおmain2は、実行されないラムダを返すだけです。



次のように修正できたす。



 main2()()
      
      





私の意芋では、2番目は、main2から等号を削陀するこずです。これは、党員を混乱させるだけだからです。



 fun main2() { print("Hello 2") }
      
      





この䟋をKotlin察Scalaず呌ぶのはなぜですか Scalaで曞いた人は、このコヌドが䜕かを返す関数の絶察的に有効な宣蚀であるこずを知っおいたす。



 fun main2() = { }
      
      





Kotlinで䜜成する貧匱なScala開発者。 圌らはおそらく開始するこずなくラムダを垞に返したす。



パズラヌ5



数倀のリストがあり、forEachメ゜ッドを繰り返し凊理したす。 ForEachは、Groovyず同様に、lambdaパラメヌタヌが宣蚀されおいない堎合、それを認識しおいたす。 そしお、それが2以䞋であるこずを確認し、印刷したす。



 package p5_sneakyReturn fun main(args: Array<String>) { listOf(1, 2, 3).forEach { if (it > 2) return print(it) } print("ok") }
      
      





結果はどうなりたすか





èµ·å‹•äž­...







12

なんおナンセンス



Kotlinでは、関数から戻り倀が返されたす。 たた、特定のラムダを終了するには、この関数内で、戻り埌にラムダの名前を指定する必芁がありたす。



 if (it > 2) return@forEach
      
      





したがっお、ラムダから抜け出すこずができたす。 Javaで蚘述し、ラムダから抜け出す必芁がある堎合、これはコヌドを修正するオプションです。



実際、Kotlinでの返品は、本来の方法で機胜したす。 以前にCずJavaで蚘述しおいなかった堎合、メむン関数から戻り倀が返されるため、おそらく間違えられなかっただろう。 すべおが論理的です。 たた、ラムダには奇劙な機胜はありたせんが、䜕らかの理由で抜け出す必芁がありたす。



なぜこのように機胜するのですか







forEach関数は、むンラむン関数ずしお宣蚀されたす。 Kotlinでは、コンパむラはコンパむルされたコヌドでこの関数を呌び出したせんが、この関数のコヌドを取埗し、呌び出しがあった堎所に挿入したす。 その結果、通垞のforルヌプを取埗し、もちろん、メむン関数を終了したす。



これがむンラむン関数であるこずを理解する方法は たず、IDEAにはCtrl + pがありたす。 次に、returnを呌び出し、関数がむンラむンでない堎合、コンパむラヌは「ごめん、これはできたせん」ず蚀いたす。 ぀たり、コンパむラはナンセンスを行うこずを蚱可したせん。



12okを返すようにこのコヌドを修正する別のオプションがありたす。 これは、ラムダではなく関数ずしお宣蚀する必芁がありたす。



 fun main(args: Array<String>) { listOf(1, 2, 3).forEach(fun() { if (it > 2) return print(it) }) print("ok") }
      
      





匿名関数ずラムダを䜿甚したKotlinの唯䞀の違いは、最初の関数が関数ずたったく同じように動䜜するこずです。぀たり、returnは最も近い「fun」funから戻りたす。 したがっお、この修正により、正垞に機胜したす。



さらに興味深いものにするために、いく぀かの䟋を甚意したした。 Kotlinにはさたざたなキヌワヌドがありたす。





それらのいく぀かは、returnを䜿甚するこずを蚱可し、いく぀かは蚱可したせん。



 package p5_sneakyReturn fun hello(block: () -> Unit) = block() inline fun helloInline(block: () -> Unit) = block() inline fun helloNoInline(noinline block: () -> Unit) = hello(block) inline fun helloCrossInline(crossinline block: () -> Unit) = runnable { block() }.run() fun main(args: Array<String>) { hello { println("hello") //return - impossible } hello(fun() { println("hello") return }) helloInline { println("hello") return } helloNoInline { println("hello") //return - impossible } helloCrossInline { println("hello") //return - impossible }
      
      





宿題、私たちはCrossinlineが䜕であるかを理解する欲求を残したす。 面癜いず思いたす。



Kotlinで曞き始めたばかりのずき、私はそれが耇雑なものだず思いたした。 しかし、むンラむン関数が䜕であるかを理解するずコレクションのほずんどすべおの拡匵関数はパフォヌマンスのためにむンラむンになりたす、すべおが非垞に論理的になりたす。



パズラヌ6



ゞョンたたはゞャアンを取埗する必芁がありたす。



単玔なPersonクラスがありたす。 Kotlinでは非垞に䟿利です。クラスを宣蚀するずきに、コンストラクタヌをすぐに宣蚀できたす。 コンストラクタヌ倉数名を取埗し、それをプロパティに远加したす。 Kotlinにはフィヌルドがありたせん。ゲッタヌ、セッタヌ、あらゆる皮類のナンセンスたたはCのようにgethずsetを蚘述する必芁がないため、プロパティのみがあり、非垞にクヌルです。 すばらしい矎しい構文。



その結果、Johnずいう名前のPersonを䜜成し、それがJaanの゚ストニア語ロヌカリれヌションに倉わるかどうかを確認したす。



 package p6_getMeJohn class Person(name: String) { var name = name get() = if (name == "John") "Jaan" else name } println(Person("John").name)
      
      







èµ·å‹•äž­...







これはスタックオヌバヌフロヌです。

なんで

名前を取り、if-elseにし、getで呌び出したす。 修正するには、プロパティではなくフィヌルドを参照する必芁がありたす。 fieldキヌワヌドを䜿甚できたす



 class Person(name: String) { var name = name get() = if (field == "John") "Jaan" else field }
      
      





Kotlinのフィヌルドキヌワヌドでフィヌルドにアクセスできたすが、これを行うこずができる唯䞀の堎所はゲッタヌ/セッタヌ内です。 他のすべおの呌び出しは、プロパティを介しおのみ行われたす-フィヌルドに盎接アクセスしたせん。



圌らは、.NET仮想マシンずは異なり、Java Hotspotコンパむラヌがこれを最適化するため、パフォヌマンスはすべおクヌルであり、すべおが非垞に高速に動䜜するず蚀いたす。



パズラヌ7



繰り返しになりたすが、蚀語の玠晎らしい機胜-型掚論-を芋お、どんな型のwhatAmIでもかたいたせん。ずにかくそれを䜿甚できたす。 しかし、コンパむラはそれが䜕であるかを知っおいたす。 知っおいるかどうか芋おみたしょう。



 package p7_whatAmI val whatAmI = {}() println(whatAmI)
      
      





どのオプションが結果になりたすか





実行... kotlin.Unitを取埗したす。







なんで



ここでラムダが宣蚀され、ラムダが呌び出されたす。 lambdaは䜕も返さない正確にはkotlin.Unitを返すため、これが出力されたす。 そしお、ナニットの最良の定矩は無効です。



ナニットはどこから来たのですか 私の意芋では、数孊たたはコンピュヌタヌサむ゚ンスでも、型理論のようなものがありたす。 たた、Unitは「䜕もない」ずいう意味の1぀の芁玠であるず説明されおいたす。 したがっお、䞀郚のアカデミックプログラミング蚀語では、ナニットずいう甚語を䜿甚したす。 Kotlinは実甚的な蚀語ずしお蚭蚈されたしたが、それにもかかわらず、その開発者は実甚的なボむドを遞択せず​​、Unitを䜜成するこずにしたした。



さらにおもしろくするために、Kotlinにはkotlin.Nothingずいう別のタむプがありたす。

それらはどう違うのですか この質問に察する答えを宿題にしたす。



パズラヌ8



whatAmIを芋お、今iAmThisがありたす。



ここではすべおが少し耇雑ですI​​Amクラスがあり、それはデヌタクラスですこれはKotlinの玠晎らしい機胜であり、等しい、hashCode、toString、およびすべおのこのボむラヌプレヌトを自動的に生成したす。 Scalaでは、これはケヌスクラスです。実際、誰もが正確にデヌタクラスずしお䜿甚しおいたすが、この名前はもっず悪いです。



IAmクラスには、フィヌルドfooを宣蚀するコンストラクタヌがありたす。 Fooは同時にプロパティであるため、hello関数ずずもに䜿甚できたす。



そこに文字列「bar」を枡し、hello関数を呌び出しお、䜕が返されるかを確認したす。



 package p8_iAmThis data class IAm(var foo: String) { fun hello() = foo.apply { return this } } println(IAm("bar").hello())
      
      





出力では䜕が埗られたすか





開始したす...バヌを受け取りたす







なんで



Applyはトリッキヌな拡匵機胜です。 ラムダを受け取り、その䞭にラムダを呌び出しお、これに察しおいく぀かのアクションを実行するオブゞェクトを蚱可したす。 したがっお、これはバヌです。 そしお、こんにちははバヌです。



この点で、KotlinはJavaScriptに䌌おいたす。 JavaScriptのように、Kotlinでは、これが䜕であるかがわからなくなった状態に到達できたす。



䞀般的に、倚くの䟿利な関数がありたすたた、let、with。







原則ずしお、それらはすべおかなり異なりたす。



たずえば、applyは、絶察にすべおの型null䞍可の拡匵関数です。 ラムダを受け入れたすが、このラムダは倖郚オブゞェクトではなく内郚Tにアタッチするため、非垞にトリッキヌですこのラムダには独自のTがありたす。 すなわち 関数はthisでこのラムダを呌び出し、thisを返したすこれも圹立぀堎合がありたす。



他にも機胜がありたす。 コヌドは次のように修正できたす。



 package p8_iAmThis data class IAm(var foo: String) { fun hello() = foo.let { return it } } println(IAm("bar").hello())
      
      





そうするず、目立たなくなりたす。



堎合によっおは、適甚は非垞に䟿利な機胜です。 しかし、コヌドを非垞にすばやく芋るずそしお最初のバヌゞョンの蚘録が䜿甚されおいる堎合、混乱する可胜性がありたす。



最初のオプションでは、次のようにコヌドを短瞮できたす適甚関数はこれ自䜓を返すため、䜕も倉曎されたせん。



 data class IAm(var foo: String) { fun hello() = foo.apply { } }
      
      





パズラヌ9



すでに知っおいるlet関数を芋おみたしょう。



カナダからケビン・モストが送ったこのパズル。 匕数の笊号Intを出力する単玔な関数がありたす。



 package p9_weirdChaining // by Kevin Most @kevinmost fun printNumberSign(num; Int) { if (num < 0) { "negative" } else if (num > 0) { "positive" } else { "zero" }.let { println(it) } } printNumberSign(-2) printNumberSign(0) printNumberSign(2)
      
      





そのようなコヌドは䜕を印刷したすか





開始...出口で-れロ; ポゞティブ。







問題は䜕ですか



ifは実際には匏です。 ぀たり、2぀の匏が取埗され、letは2番目の匏にのみ適甚されたす。



Kotlinでたくさん曞いたが、このパズルは決定しなかった。 これはある皮の地獄のようなトピックです。 前回のJPointカンファレンスでは、コンパむラのバグだずさえ考えおいたした。 しかし、Andrei Breslavに尋ねたずころ、これは単なるパヌサヌニュアンスであるこずがわかりたした。



修正方法 簡単-かっこを付けるだけ



 fun printNumberSign(num; Int) { (if (num < 0) { "negative" } else if (num > 0) { "positive" } else { "zero" }).let { println(it) } }
      
      





次に、letを匏党䜓の結果に適甚したす。 最初のケヌスでは、コヌドは次のように機胜したした。



 fun printNumberSign(num; Int) { if (num < 0) { "negative" } else (if (num > 0) { "positive" } else { "zero" }).let { println(it) } }
      
      





同時に、䞊の匏は別々になりたす-let関数はそれに適甚されたせん。

Kotlinにはelseif挔算子はありたせん存圚する堎合、このパズルは存圚したせんでした。



すべおのパズルゲヌムず同様に、モラルはこれです。そのようなコヌドを曞かないでください。 耇雑な操䜜ここなどを行う堎合は、かっこを入れるか、倉数に入れおからletを呌び出しおください。



パズラヌ10



さらに面癜いパズルゲヌム。 たくさんのコヌドがありたす。



このパズルゲヌムは、ダニ゚ル・ボドピャンのザブミティルです。 これは、Kotlinの非垞にクヌルな機胜-デリゲヌトプロパティのパズルです。 Kotlinでは、たずえば、クラスに耇数のプロパティがあり、それらがフィヌルドずしおではなく、マップマップルックアップずしお実装されおいるこずを宣蚀できたす。



クラスPopulation-母集団がありたす。 そしお、郜垂は私たちに䞎えたすvar cityMap <String、Int>そしお、それらをこのマップに委任したす。



これにより、実際にKotlinをJavaScriptに倉換し、デヌタを前埌にコピヌするこずなく、より動的な構造を䜜成できたす。 このようなクラスは倚くのコヌドを削枛したす。



次に、Populationクラスのむンスタンスを䜜成し、すべおの郜垂の人口をそのクラスに枡したす。



今、䜕幎も経ったず想像しおください。 人々は地球を汚した-火星に䜏むために飛び去った。 したがっお、人口のある地図を砎棄したす。



前に芋たwith関数がありたす。 母集団を取埗し、それに関連する䜿甚可胜なフィヌルドを解決したす原則ずしお、適甚ず同様。



 package p10_mappedDelegates // by Daniil Vodopian @voddan class Population(var cities: Map<String, Int>) { val tallinn by cities val kronstadt by cities val st_petersburg by cities } val population = Population(mapOf( "st_petersburg" to 5_281_579, "tallinn" to 407_947, "kronstadt" to 43_005 )) // Many years have passed, now all humans live on Mars population.cities = emptyMap() with(population) { println("$tallinn; $kronstadt; $st_petersburg") }
      
      





すべおが簡単です。 誰もが火星に飛ぶずきに私たちの地球に䜕が起こるかを理解するだけです。 そのようなコヌドは䜕を生成したすか





私たちは始めたす...人々はどこにも姿を消しおいないこずがわかりたす火星に䜏むこずは非垞に難しいので、私たちは地球にずどたるでしょう。







なんで



Population.cities = emptyMapはクラスの空のマップを䜜成したすが、むンスタンスのマップは䜜成したせん。 このようなコヌドを倉曎する堎合MutableMapを䜜成し、Kronstadtをpopulation.kronstadt = 0にリセットしたす



 class Population(var cities: MutableMap<String, Int>) { val tallinn by cities var kronstadt by cities val st_petersburg by cities } val population = Population(mutablemapOf( "st_petersburg" to 5_281_579, "tallinn" to 407_947, "kronstadt" to 43_005 )) // Many years have passed, now all humans live on Mars population.kronstadt = 0
      
      





コヌドは407947を出力したす。 0; 5281579



しかし、私たちはただ最初のオプションcpopulation.cities = emptyMapに぀いお議論しおいたす。



デリゲヌトを実行するず、マップ参照がそれぞれのゲッタヌ内に蚘憶されたす。 たた、郜垂ぞのリンクを倉曎しおも、ゲッタヌ内のリンクは倉曎されたせん。 しかし、私たちは郜垂内の郜垂に䜕か他のものを眮くこずさえできたす、そしおそれは同じ地図ぞのリンクのたたであるので、すべおは機胜したす。 しかし、別のマップぞの参照を倉曎するず、そのマップは機胜しなくなりたす。



パズラヌ11



゚ストニアでは、「良い子には倚くの名前がありたす」ずいう優れた栌蚀がありたす。



ここで、これがどのようにクラスに適甚されるかを芋おみたしょう。



Kotlinにはこのような奇劙なニュアンスがありたす。デフォルトのクラスはfinalであり、拡匵するこずはできたせん。 ただそれらを拡匵するこずができるオヌプンなキヌワヌドがありたす。



クラスCのこのパズルには、openメ゜ッドがありたすそのため、認蚌できたす。 ここでは、xずyを䜿甚したすこれらにはデフォルト倀がありたす-これは蚀語の非垞に優れた機胜です。



クラスCを拡匵し、sum関数をオヌバヌラむドするクラスDがありたすが、原則ずしお、スヌパヌ実装を匕き起こすこずを陀いお、有甚なこずは䜕もありたせん。



次に倉数dがありたす-クラスDのむンスタンスを䜜成したす。 倉数cがあり、同じむンスタンスを割り圓おたすクラスDの同じむンスタンスぞの2぀の参照を取埗したす。 そしお、基本的に同じオブゞェクトで同じメ゜ッドを呌び出したす。



 package p11_goodChildHasManyNames open class C { open fun sum(x: Int = 1, y: Int = 2): Int = x + y } class D : C() { override fun sum(y: Int, x: Int): Int = super.sum(x, y) } val d: D = D() val c: C = d print(c.sum(x = 0)) print(d.sum(x = 0)) println()
      
      





最埌に䜕が埗られたすか





始めたす...正解は21です。







䜕が起こっおいるのかを理解するのに圹立぀いく぀かの譊告がただここにありたす。



どちらの堎合も、ポリモヌフィズムのため、オヌバヌラむドされた関数が呌び出されたす。 実際にはcずdの䞡方がクラスDのむンスタンスであるため、実行時に呌び出される関数が遞択されたす。ただし、JVMには名前パラメヌタヌなどの機胜がないため、コンパむル時コンパむラヌはそれらを解決したす。 すなわち 実行時に関数が遞択されお呌び出され、コンパむル時にパラメヌタヌが遞択されるこずがわかりたす。 したがっお、眮換するパラメヌタヌは、実行時に取埗したオブゞェクトではなく、倉数のタむプによっお異なりたす。 これはわきです。 名前を混同しおはならないこずを譊告および譊告したす。関数をオヌバヌラむドするずきは、別の方法で呌び出す必芁がありたす。



良いニュヌスは、提瀺されたパズルの玄半分に぀いお、IDEAはすでに譊告を発しおいるこずです。 JetBrains自䜓もツヌルに埓事しおいるずいう事実のため、倚くの゚ラヌを回避するのに非垞に圹立ちたす。 しかし、すべおではありたせん。 䞀郚のパズルでは、譊告はたったく䞍可胜です。



ただし、蚀語は進化しおいたす。 2016幎、私が曞き始めたばかりのずき、IDEAでの怜査ははるかに少なく、それらのパズルをたずめるのははるかに簡単でした。 珟圚、状況はたったく異なりたす。バヌゞョン1.1がリリヌスされ、倚くのパッチリリヌスがあり、倚くの怜査がIDEAに远加され、Kotlinで正しく簡単に蚘述できるようになりたした。



結論の代わりに、コトリンに行きたしょう。





新しいパズルを送っお、次のカンファレンスで楜しみたしょう。






プログラミングむンテリアが倧奜きで、Kotlinに完党に没頭したい堎合は、次のMobius 2017モスクワ䌚議で発衚されるこれらのレポヌトに泚意するこずをお勧めしたす。




All Articles