Kotlinの抂芁ずCずの比范

著者から


この蚘事では、膝に関する泚意事項を玹介したす。構文に぀いおは、C蚀語ずのわずかな比范など、Kotlinの簡単な抂芁です。 これは私の意芋であり、Javaプラットフォヌムの䞖界でこの比范的若い蚀語に぀いおの私の考えであり、私の意芋では成功する可胜性が高いです。


Kotlinは、JavaプラットフォヌムおよびJavaScript甚にコンパむルされた静的に型指定されたオブゞェクト指向プログラミング蚀語です。 2010幎からJetBrainsによっお開発されたした。 同時リリヌスはそれほど前ではありたせんでした。 著者は、Javaよりも簡朔でタむプセヌフで、Scalaよりもシンプルな蚀語を䜜成するこずを目指したした。 たた、Scalaず比范しお簡玠化されたため、IDEでのコンパむルが高速になり、蚀語サポヌトが向䞊したした。 ずりわけ、䌚瀟がこの蚀語の開発を発衚したずき、開発者がScalaのプラグむンを思い起こさせた方が良いずの批刀が殺到したした私が理解するず、ただ通垞のIDEはありたせん。 しかし、䌁業にずっおプログラミング蚀語は非垞に重芁なツヌルであり、Java開発者は急いで新しい機胜を蚀語に導入するこずはありたせん。 そしお、ポむントは圌らがそれを望んでいないずいうこずではなく、あたりにも倚くのコヌドが曞かれおおり、あたりにも倚くのシステムがこのプラットフォヌムで動䜜しおいるからです。 そしお今、あなたはバラストのようにあなた自身のために埌方互換性を匕き出す必芁がありたす。 たた、蚀語の最埌の8バヌゞョンで新しい機胜ラムダ匏などが远加されたずしおも、゚ンタヌプラむズの䞖界はJVMの曎新を急ぐこずはありたせんでした。 経隓が瀺すように、䞀郚のカスタムメむドの䌁業や䌁業は 、マシンをバヌゞョン7にのみ曎新しおおり、システム内の数癟台のマシンをバヌゞョン8に曎新するこずは、顧客の䌚瀟にずっおあたり䟿利で高䟡ではありたせん。 私の芳点からは、開発䞭の蚀語のこのような遅延は、十分に開発された匷力なツヌルであり、䜿甚頻床を知るこずができるず特城づけおいたす。 ただし、他のJava蚀語ず比范するず、冗長に芋える堎合がありたすが、これは、Cで十分にプログラミングし、たずえばコヌドをよりコンパクトにする同じLINQ、ラムダ匏、その他の構文シュガヌパンを䜿甚した人ずしおの私の意芋です。
そのため、JetBrainsの人々は、Javaずの完党な互換性を備え、プログラマの日々の䜜業を簡玠化し、生産性を向䞊させる远加機胜を提䟛する蚀語を䜜成するこずにしたした。

知人...


私は偶然圌に出䌚いたした。 Javaでのプログラミングでは、Cの利点を逃したした。どうにかしお自分自身を喜ばせ、顧客の芁件を満たしたいず思いたす。 Kotlinのドキュメントを確認した埌、これが必芁なものであるこずに気付きたした。 150ペヌゞのドキュメントは読みやすく、蚀語は孊習しやすく、簡朔です。 ただし、Cずの共通点が十分にあり、蚀語での䜜業がさらに快適になるずいう事実に぀いお最も気に入っおいたす。 それでも、.NETを忘れたくありたせん。

グッズ...


クラスを操䜜する


さお、今から最も興味深いものに移り、蚀語の機胜のいく぀かず私がそれに぀いお奜きなこずを考えおみたしょう。
Kotlinでクラスを宣蚀する方法
class Man { var name: String //var -   , val -   var age: Int constructor(name: String, age: Int) { this.name = name this.age = age } } 

コンストラクタヌがコンストラクタヌキヌワヌドでタグ付けされおいるこずを陀いお、ほずんど異垞なこずはありたせん。 これは、実際にはKotlinaの芳点から芋るずセカンダリコンストラクタヌであり、プラむマリコンストラクタヌたたはプラむマリコンストラクタヌはクラスヘッダヌの䞀郚です。
 class Man constructor(var name: String, var age: Int) //      class Man (var name: String, var age: Int) 

たったく同じ構文は、前述のコヌドず同等です。 倉数名ず幎霢もクラスに存圚し、それぞれvarかなり興味深い機胜を䜿甚しおプラむマリコンストラクタヌで䜜成されたした。 䞀芋普通ではありたせんが、しばらくするず非垞に䟿利だず気づきたす。 ただし、メむンコンストラクタヌにはコヌドを含めるこずができないため、オブゞェクトが䜜成されるたびに呌び出される初期化ブロックinitがありたす。
 class Man (var name: String, var age: Int){ init { //-  } } 

私の意芋に興味深い。 コンストラクタヌのチェヌンを䜜成するこずもできたす。
 class Man (var name: String){ var name: String? = null //,  null,        ,    ,   C# var age: Int = 0 //   ,    , getter  setter    constructor(name: String, age: Int) : this(name) { this.age = age } } 

宣蚀のプロパティず完党な構文は、ここで興味深い実装がされおいたす。
 var <propertyName>: <PropertyType> [= <property_initializer>] [<getter>] [<setter>] 

最初の䟋に瀺すように、クラスを蚘述する堎合、初期化子、ゲッタヌ、およびセッタヌはオプションです。 倉数がvalずしお蚘述されおいる堎合、セッタヌはそれに応じお犁止されおいたす。 プロパティの説明方法
 class Man { var name: String get() { return "Name man: $field" //field -   ,     .  getter    , field      } private set(value) { //       field = value } var age: Int constructor(name: String, age: Int) { this.name = name this.age = age } } 

デヌタクラス


興味深いのはデヌタクラスです。 これらのクラスは、デヌタを保存するために䜿甚され、他には䜕もしたせん。 コンパむラは、メむンコンストラクタヌで宣蚀されたすべおのプロパティから自動的にメンバヌを掚枬したす。

これにより、このタむプのクラスを操䜜するずきに䟿利になりたす。
 data class Man (var name: String, var age: Int) fun main(args: Array<String>) { var man = Man("Alex", 26) //     new println(man) // Man(name=Alex, age=26) //  val (name, age) = man //  : val name = man.component1(); val age = man.component2(); println(name) // Alex println(age) // 26 // copy() var man2 = man.copy() //  ,   var man2 = man.copy(age = 20) // ,     println(man2) //Man(name=Alex, age=20) } 

このクラスの説明で、私は蚀語のその郚分であるハむラむトである郚分を終了しお次に進みたいず思いたす。

関数ずラムダ


Kotlinの関数はfunキヌワヌドを䜿甚しお宣蚀され、特定のクラスにバむンドされるこずなくグロヌバルに定矩できたす。
 fun f1(x: Int): Int { return x * 2 } //  fun f1(x: Int): Int = x * 2 //   fun main(args: Array<String>) { println(f1(5)) // 10 } 

関数は、次の堎合に挿入蚘法を䜿甚しお呌び出すこずもできたす。

 //   Int infix fun Int.extent(x: Int): Int { return this + x } //  infix fun Int.extent(x: Int) = this + x fun main(args: Array<String>) { // -   infix  println(5 extent 10) // 15 //   println(5.extent(10)) } 

関数には、名前付きパラメヌタヌずデフォルトの匕数倀もありたす。
可倉数の匕数を枡すこずができたす。
 fun <T> asList(vararg ts: T): List<T> { val result = ArrayList<T>() for (t in ts) // ts is an Array result.add(t) return result } fun main(args: Array<String>) { val list = asList(1, 2, 3) // ,     } 

ロヌカル関数がサポヌトされおいたすC7.0もこの関数を実装したした
 fun f1(x: Man): String { fun isTeenager(age: Int): Boolean { return age in 13..19 } if (isTeenager(x.age)) return "Man teenager" return "Man is not a teenager" } 

高階関数ずラムダ匏


特に興味深いのは、蚀語のこの郚分です。 高階関数は通垞、他の関数を匕数ずしお取る関数、たたは結果ずしお別の関数を返す関数ず呌ばれたす。 さらに、䞻なアむデアは、関数が他のデヌタオブゞェクトず同じステヌタスを持぀こずです。 高階関数を䜿甚するず、蚈算の耇雑さを考慮しお、抜象的でコンパクトなプログラムが䜜成されたす。
高階関数の䟋を考えおみたしょう。
 //   ,    ,     fun<T> List<T>.filter(transform: (T) -> Boolean): List<T> { val result = arrayListOf<T>() for (item in this) { if (transform(item)) { result.add(item) } } return result } fun main(args: Array<String>) { val list = arrayListOf(1, 4, 6, 7, 9, 2, 5, 8) val listEven = list.filter { item -> item % 2 == 0 } listEven.forEach { item -> print(item.toString() + " ") } // : 4 6 2 8 } 

このアプロヌチにより、LINQスタむルのコヌドを蚘述できたす。
 strings.filter { it.length == 5 }.sortBy { it }.map { it.toUpperCase() } 

ラムダ匏の完党な構文は次のずおりです。
 val sum = { x: Int, y: Int -> x + y } 

さらに、远加の泚釈を残すず、次のようになりたす。
 val sum: (Int, Int) -> Int = { x, y -> x + y } 

括匧内には、パラメヌタヌが垞に瀺されおおり、->を䜿甚しお本䜓に転送されたす。
ラムダ匏の構文に欠けおいるものの1぀は、戻り倀の型を指定する機胜です。 ほずんどの堎合、戻り倀の型は自動的に掚枬されるため、これは䞍芁です。 ただし、明瀺的に指定する必芁がある堎合は、別の構文、 匿名関数を䜿甚できたす。
 fun(x: Int, y: Int): Int = x + y //  val listEven = list.filter(fun(item) = item % 2 == 0) 

関数のカリヌ化ず郚分的な適甚


䟋ずしお関数のカリヌ化ず郚分的な適甚を怜蚎し、KotlinずCの実装を比范したす。
䞀郚の人々 は、関数の カリヌ化ず郚分的な䜿甚ずいう甚語を混同しそしお、少し前にやった、それらを亀換可胜に䜿甚したす。 カリヌ化ず郚分適甚の䞡方は、ある皮の機胜を別の皮類に倉換する方法です。

郚分関数の䜿甚


郚分的なアプリケヌションは、N個のパラメヌタヌずこれらのパラメヌタヌのいずれかの倀を持぀関数を取り、N-1パラメヌタヌを持぀関数を返したす。そのため、呌び出されるず、必芁なすべおの倀郚分アプリケヌション関数自䜓に枡される最初の匕数ず、残りのN-1戻り関数に枡される匕数。 したがっお、これらの2぀の呌び出しは、3぀のパラメヌタヌを持぀メ゜ッドず同等でなければなりたせん。 Cでは、これにデリゲヌトが䜿甚されたす。 もちろん、これらは高階関数の完党な代替物ではありたせんが、実蚌するには十分です。
  class Program { static Int32 SampleFunc(Int32 a, Int32 b, Int32 c) { return a + b + c; } //  ApplyPartial             static Func<T2, T3, TResult> ApplyPartial<T1, T2, T3, TResult> (Func<T1, T2, T3, TResult> function, T1 arg1) { return (b, c) => function(arg1, b, c); } static Func<T3, TResult> ApplyPartial<T2, T3, TResult> (Func<T2, T3, TResult> function, T2 arg2) { return (c) => function(arg2, c); } static Func<TResult> ApplyPartial<T3, TResult> (Func<T3, TResult> function, T3 arg3) { return () => function(arg3); } static void Main(string[] args) { Func<Int32, Int32, Int32, Int32> function = SampleFunc; Func<Int32, Int32, Int32> partial1 = ApplyPartial(function, 1); Func<Int32, Int32> partial2 = ApplyPartial(partial1, 2); Func<Int32> partial3 = ApplyPartial(partial2, 3); var resp = partial3(); //      Console.WriteLine(resp); Console.ReadKey(); } } 

䞀般化により、ApplyPatrialメ゜ッドは実際よりも芋た目が難しくなりたす。 Cに高次型が存圚しないずいうこずは、䜿甚するデリゲヌトごずにメ゜ッド実装が必芁であるこずを意味したす。 これには、アクションファミリが必芁になる堎合がありたす。
Kotlinサンプルコヌド
 fun sampleFunc(a: Int, b: Int, c: Int): Int { return a + b + c } fun f3(a: Int, b: Int): Int { return sampleFunc(a, b, 3) } fun f2(a: Int): Int { return f1(a, 2) } fun f1(): Int { return f2(1) } //    - val sampleFunc = { a: Int, b: Int, c: Int -> a + b + c } val f3 = { a: Int, b: Int -> sampleFunc(a, b, 3) } val f2 = { a: Int -> f3(a, 2) } val f1 = { -> f2(1) } fun main(args: Array<String>) { println(f1()) // 6 } 

Kotlinでは、Cず同様に、N-1個の匕数を持぀関数を取埗するために、別個の関数オブゞェクトを䜜成する必芁がありたす。 蚀語のアプロヌチは同じですが、Kotlinでのみ構文がコンパクトであるため、これを行う方が䟿利です。

キャリング


郚分アプリケヌションは、1぀の匕数を䜿甚しおN個のパラメヌタヌを持぀関数をN-1個のパラメヌタヌを持぀関数に倉換したすが、カリヌ化は関数を1぀の匕数の関数に分解したす。 倉換された関数を陀いお、Curryメ゜ッドに远加の匕数を枡したせん。

Cでの実装は次のようになりたす。
  class Program { static Int32 SampleFunc(Int32 a, Int32 b, Int32 c) { return a + b + c; } static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult> (Func<T1, T2, T3, TResult> function) { return a => b => c => function(a, b, c); } static void Main(string[] args) { Func<Int32, Int32, Int32, Int32> function = SampleFunc; //    Func<Int32, Func<Int32, Func<Int32, Int32>>> f1 = Curry(function); Func<Int32, Func<Int32, Int32>> f2 = f1(1); Func<Int32, Int32> f3 = f2(2); Int32 result = f3(3); //     ... var curried = Curry(function); result = curried(1)(2)(3); Console.WriteLine(result); // 6 Console.ReadKey(); } } 

コトリンコヌド
 fun curry(body: (a: Int, b: Int, c: Int) -> Int): (Int) -> (Int) -> (Int) -> Int { return fun(a: Int): (Int) -> (Int) -> Int { return fun(b: Int): (Int) -> Int { return fun(c: Int): Int = body(a, b, c) } } } //   fun curry(body: (a: Int, b: Int, c: Int) -> Int) = fun(a: Int) = fun(b: Int) = fun(c: Int) = body(a, b, c) fun main(args: Array<String>) { val f = curry { a: Int, b: Int, c: Int -> a + b + c } val response = f(1)(1)(1) println(response) } 

むンラむン関数


より高い関数を䜿甚するず、オヌバヌヘッドが発生したす。 関数オブゞェクトのメモリの割り圓お、およびその埌のクリヌニング。 倚くの堎合、この皮のオヌバヌヘッドは、ラムダ匏を眮き換えるこずで排陀できたす。 パラメヌタヌずしお関数を受け取り、ロックオブゞェクトず関数を受け取り、ロックを受け取り、関数を実行し、ロックを解陀する関数を考えたす。
 fun <T> lock(lock: Lock, body: () -> T): T { lock.lock() try { return body() } finally { lock.unlock() } } 

ただし、呌び出されるず、オブゞェクトが䜜成されたす。 オブゞェクトを䜜成する代わりに、コンパむラは次のコヌドを挿入できたす。
 l.lock() try { foo() } finally { l.unlock() } 

コンパむラヌにこれを匷制するには、メ゜ッド宣蚀にむンラむン修食子を远加する必芁がありたす。
 inline fun lock<T>(lock: Lock, body: () -> T): T { // ... } 

ただし、倧きな関数を埋め蟌たないでください。これはパフォヌマンスに圱響する堎合がありたす。 すべおの関数を埋め蟌む必芁がない堎合は、noinline修食子を远加できたす。
 inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { // ... } 


結論...


コトリンは、孊ぶのが楜しい面癜い蚀語です。 コンパクトな構文ずそれが提䟛する幅広い可胜性が気に入っおいたす。 別のメリットずしお、1぀のプロゞェクトでJavaず䞀緒に䜿甚できるずいう事実に蚀及する䟡倀がありたす。これは非垞に興味深いこずであり、プロゞェクトを䜜成する際に非垞に柔軟性がありたす。 この蚀語を䜿甚するず、プログラムをすばやく開発し、非垞にうたく実行できたす。 同じCを䜿甚した同様の構文により、孊習がさらに容易になり、より優れたものになりたす。 したがっお、誰かが突然.NETプラットフォヌムからJavaプラットフォヌムに切り替えたい堎合、この蚀語は良い印象を残すかもしれたせん。

PS Javaプログラマヌずしおのこの蚀語ずCに぀いおの興味深い意芋。 プロゞェクトでKotlinを䜿甚したすか

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


All Articles