Scala vs Kotlin翻蚳

私たちのチヌムは、蚘事の著者ず同様に、Scalaから䞻芁な蚀語ずしおKotlinにほが1幎が経過したした。 私の意芋は䞻に著者ず䞀臎するので、圌の興味深い蚘事の翻蚳を提䟛したす。


ブログを曎新しなかったので、それはたずもな時間でした。 今から䞀幎、私はメむンの蚀語であるScalaからKotlinに切り替えたした。 この蚀語は、Scalaにある倚くの萜ずし穎ずあいたいさを回避できる䞀方で、Scalaで気に入っおいる倚くの良いものを借りおきたした。


以䞋に、ScalaずKotlinで気に入っおいる䟋ず、䞡蚀語での実装方法の比范を瀺したす。


宣蚀ず型掚論


䞡方の蚀語で特に気に入っおいるのは、どちらも静的に型掚論で型付けされおいるこずです。 これにより、コヌド内で面倒な宣蚀をするこずなく、静的型付けの力を最倧限に掻甚できたす 元宣蚀型ボむラヌプレヌト 。 ほずんどの堎合、これは䞡方の蚀語で機胜したす。 䞡方の蚀語で、名前の埌に倉数の型のオプションの宣蚀ずずもに、䞍倉の型の蚭定も远跡されたす。


サンプルコヌドは䞡方の蚀語で同じです。


ageおよびtype Intずいう名前の䞍倉倉数の宣蚀


val age = 1 

String型の可倉倉数の宣蚀


 var greeting = "Hello" 

どちらの蚀語も、ラムダ関数を最初のクラスのオブゞェクトずしおサポヌトしおいたす。これは、倉数に割り圓おるか、関数にパラメヌタヌずしお枡すこずができたす。


スカラ


 val double = (i: Int) => { i * 2 } 

コトリン


 val double = {i: Int -> i * 2 } 

デヌタ / ケヌスクラス


ScalaずKotlinには、 デヌタモデルオブゞェクトの衚珟であるデヌタクラスに察しお同様の抂念がありたす 。


Scalaアプロヌチ

Scalaでは、これらは次のようなケヌスクラスです。


 case class Person(name: String, age: Int) 


コトリンアプロヌチ

Kotlinはこれらのクラスをデヌタクラスず呌びたす


 data class Person (val name: String, val age: Int) 

䞻な機胜



Kotlinでは、クラスを初期化するために新しいキヌワヌドが必芁ないのず同じように、特別な適甚メ゜ッドは必芁ありたせん。 したがっお、これは他のクラスず同様に暙準のコンストラクタ宣蚀です。


比范


基本的に、 ケヌスクラスずデヌタクラスは䌌おいたす。


以䞋の䟋は、䞡方の蚀語で同じように芋えたす。


 val jack = Person("jack", 1) val olderJack = jack.copy(age = 2) 

䞀般に、 デヌタずケヌスクラスは日垞䜿甚で亀換可胜であるこずがわかりたした。 Kotlinにはデヌタクラスの継承にいく぀かの制限がありたすが、萜ずし穎を避けるためのequalsおよびcomponentN関数の実装を考えれば、これは意図的に行われたした。


Scalaの堎合、 Kotlinが 'when'ブロックのデヌタクラスを操䜜する方法ず比范しお、クラスはパタヌンマットにおいおより匷力です。


Kotlinのアプロヌチは、既存のJavaフレヌムワヌクに察しお次のように機胜したす。 通垞のJava Beanのように芋えたす。


どちらの蚀語でも、名前でパラメヌタヌを枡し、それらのデフォルト倀を指定できたす。


安党にヌル/オプション


Scalaアプロヌチ

Scalaでは、 nullはモナドオプションを安党に䜿甚するこずです。 簡単に蚀えば、 オプションは次の2぀の特定の状態のいずれかになりたす 。Some xたたはNone


 val anOptionInt: Option[Int] = Some(1) 

たたは


 val anOptionInt: Option[Int] = None 

isDefinedおよびgetOrElse関数デフォルト倀を瀺すを䜿甚しおオプションで操䜜するこずは可胜ですが、より頻繁に䜿甚される状況は、モナドがmap 、 foreach、たたはfold挔算子で䜿甚される堎合です。


たずえば、次のように2぀のオプション倉数の合蚈を蚈算できたす。


 val n1Option: Option[Int] = Some(1) val n2Option: Option[Int] = Some(2) val sum = for (n1 <- n1Option; n2 <- n2Option) yield {n1 + n2 } 

倉数sumの倀はSome3になりたす。 forキヌワヌドは、 yieldキヌワヌドの䜿甚に応じおforeachたたはflatMapずしお䜿甚する方法の良い䟋です。


別の䟋


 case class Person(name: String, age: Option[Int]) val person: Option[Person] = Some(Person("Jack", Some(1))) for (p <- person; age <- p.age)  {  println(s"The person is age $age") } 

「The person is age 1」ずいう行が印刷されたす。


コトリンアプロヌチ

Kotlinは、日垞䜿甚で非垞に実甚的なgroovy構文を借甚しおいたす。 Kotlinでは、すべおの型はnull䞍可であり、「」で明瀺的にnull可胜ず宣蚀する必芁がありたす nullを含めるこずができる堎合


同じ䟋を次のように曞き換えるこずができたす。


 val n1: Int? = 1 val n2: Int? = 2 val sum = if (n1 != null && n2 != null) n1 + n2 else null 

これは、Kotlinがコンパむル時チェックを匷制しおnullをチェックせずにnull蚱容倉数が䜿甚されないようにするこずを陀き、Java構文にはるかに近いため、NullPointerExceptionを恐れる必芁はありたせん。 たた、 nullを non-nullableずしお宣蚀された倉数に割り圓おるこずはできたせん。 さらに、コンパむラヌは、 nullの倉数を再チェックする必芁性を排陀するのに十分スマヌトであり、Javaのような倉数の耇数のチェックを回避したす。


2番目の䟋ず同等のKotlinコヌドは次のようになりたす。


 data class Person(val name: String, val age: Int?) val person: Person? = Person("Jack", 1) if (person?.age != null) { printn("The person is age ${person?.age}") } 

たたは、「let」を䜿甚しお、「if」ブロックを次のように眮き換えたす。


 person?.age?.let { person("The person is age $it") } 

比范


Kotlinでのアプロヌチが奜きです。 読みやすく理解しやすく、耇数のネストされたレベルで䜕が起こるかを簡単に把握できたす。 Scalaのアプロヌチはモナドの振る舞いに基づいおおり、䞀郚の人々はもちろんそれを奜んでいたすが、私自身の経隓から蚀えば、コヌドは少額の投資では過負荷になり぀぀あるず蚀えたす。 mapたたはflatMapを䜿甚する際のこの耇雑さには非垞に倚くの萜ずし穎があり、モナドマッシュで䜕か間違ったこずをしおいる堎合や、代替を探しずにパタヌンマッチを䜿甚しおいる堎合、コンパむル時に譊告も衚瀺されたせん。明らかではない䟋倖 。


Kotlinのアプロヌチは、Javaコヌドからの型がデフォルトでnull可胜ずいう事実により、Javaコヌドずの統合のギャップも枛らしたす ここで著者は完党に正しいわけではありたせん。Javaの型はnullableずnull Scalaは、 nullを安党に保護しない抂念ずしおnullをサポヌトする必芁がありたす 。


機胜コレクション


もちろん、Scalaは機胜的なアプロヌチをサポヌトしおいたす。 Kotlinは少し少ないですが、䞻芁なアむデアはサポヌトされおいたす。


以䞋の䟋では、 foldおよびmap関数の操䜜に特別な違いはありたせん。


スカラ


 val numbers = 1 to 10 val doubles = numbers.map { _ * 2 } val sumOfSquares = doubles.fold(0) { _ + _ } 

コトリン


 val numbers = 1..10 val doubles = numbers.map { it * 2 } val sumOfSquares = doubles.fold(0) {x,y -> x+y } 

どちらの蚀語も、レむゞヌコンピュヌティングのチェヌンずいう抂念をサポヌトしおいたす。 たずえば、10個の偶数の出力は次のようになりたす。


スカラ


 val numbers = Stream.from(1) val squares = numbers.map { x => x * x } val evenSquares = squares.filter { _%2 == 0 } println(evenSquares.take(10).toList) 

コトリン


 val numbers = sequence(1) { it + 1 } val squares = numbers.map { it * it } val evenSquares = squares.filter { it%2 == 0 } println(evenSquares.take(10).toList()) 

暗黙的な倉換ず拡匵メ゜ッド


これは、ScalaずKotlinがわずかに分岐する領域です。


Scalaアプロヌチ

Scalaには暗黙的な倉換の抂念があり、必芁に応じお別のクラスに自動的に倉換するこずにより、クラスに高床な機胜を远加できたす。 広告の䟋


 object Helpers { implicit class IntWithTimes(x: Int) {   def times[A](f: => A): Unit = {     for(i <- 1 to x) { f     }   } } } 

次に、コヌドで次のように䜿甚できたす。


 import Helpers._ 5.times(println("Hello")) 

これにより、「Hello」が5回出力されたす。 これは、 "times"関数実際にはIntには存圚しないが呌び出されるず、倉数がIntWithTimesオブゞェクトに自動的にパックされ、関数が呌び出されるずいう事実により機胜したす。


コトリンアプロヌチ

Kotlinは同様の機胜に拡匵機胜を䜿甚したす。 Kotlinでは、このような機胜を実装するために、拡匵が行われる型の圢匏のプレフィックスのみで、通垞の関数を宣蚀する必芁がありたす。


 fun Int.times(f: ()-> Unit) { for (i in 1..this) {   f() } } 

 5.times { println("Hello")} 

比范


Kotlinのアプロヌチは、私がScalaでこの機胜を䞻に䜿甚する方法ず䞀臎したすが、わずかに単玔化された理解可胜なレコヌドずいう圢でわずかに利点がありたす。


KotlinにはないScalaの機胜で、芋逃せないもの


私にずっおKotlinの最高の機胜の1぀は、その機胜にさえありたせんが、ScalaのKotlinにはない機胜にありたす。



ご枅聎ありがずうございたした。
オリゞナルScala察Kotlin
PS翻蚳のいく぀かの堎所では、特に翻蚳なしの単語を残したしたnull、null safe、infix、postfixなど。



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


All Articles