Kotlin

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動
Wikipedia
ウィキペディアKotlinの記事があります。

メインページ > 工学 > 情報技術 > プログラミング > Kotlin


Kotlin(コトリン)とは、JetBrainsによってJavaの問題点を改善しようと作られたオブジェクト指向型プログラミング言語である。 主な特徴はJavaとの相互運用性をできるだけ高めていること、および従来はアノテーションによるヒントでしかなかった値や式やフィールド、メソッドの返り値がnullの可能性があるかどうかを型システムの中に取り入れ、Null安全を保証していることである。 2019年にはw:Googlew:Androidのアプリ開発用言語として採用した。[1]

目次[編集]

未分類の下書き[編集]

※ 完成次第、サブページに移動してください。

予備知識

現状の版では、読者に予備知識として、ある程度のC言語やJavaScriptの知識を想定しています。もし読者がこれら予備知識の言語にそこまで詳しくなければ、先に『C言語』および『JavaScript』をお読みください。

なお、Javaの知識はあるにこしたことないですが、必ずしも必要ではありません。

Javaなどにある「クラス」を Kotlin でもサポートしており、Javaと同様にKotlin でも class 宣言でクラスを作成できます。しかし、読者がまったくクラスについて知らなくても、Kotlin による開発を比較的に簡単に始めることが可能です。

文法の概要[編集]

hello world[編集]

Kotlinの文法は、Javaと大きく異なる。

以下に示すのはKotlinでのw:ハローワールドのコードである。

// Hello.kt
fun main(args: Array<String>) {
    println("Hello, World!")
}

じつは、これはもっと短くでき、[注 1][2]

// ShortHello.kt
fun main() {
    println("Hello, World!")
}

と書いてもいい。

funというのは、関数を宣言する宣言子である。JavaScriptで言うfunctionである。

printlnというのは、コマンド画面などに、文字表示をする組み込み関数のことである。[3]

printlnは、文末に改行が自動で入る。[3]

JavaやC言語などと違い、文末にセミコロン (;) は必要ない。

その他の例[編集]

まずはコード例を見てみましょう。

コード例
fun main() {
    var mes : String // (1)
    mes = "テストです"
    println(mes)
    
    var kazu : Int // (2)
    kazu = 5
    println(kazu * 3)
        
}


実行結果
テストです
15


解説

変数を宣言するときは、

var 変数名 : 型名

という書式で宣言する。

なお、Kotlin の型名はJava同様、大文字のキャメルケースであるのが通例である。 上記のコードの (1) では、mesというkotlin.String型の変数を、 (2) では、kazuというkotlin.Int型の変数を宣言している。 valを用いることもできるが、valで宣言された場合は再度代入することができない。

var は variable (変数)の略。
val は value (値)の略。

文字表示と標準入出力の概要[編集]

文字の連結[編集]

println関数などで2個以上の文字列を連結したい場合は、+演算子でつなぎあわせる。

コード例
fun main() {
    var mes : String
    mes = "テストです"
    println(mes)
    
    var kazu : Int
    kazu = 5
    println(kazu * 3)
        
    println(mes + kazu)
}


実行結果
テストです
15
テストです5

※ 変数 kazu 自体の中身は15ではなく5。

式が要求されている箇所で、kotlin.Stringでない型の変数にkotlin.String型の変数を、あるいはkotlin.String型の変数にkotlin.Stringでない型の変数を足すと、自動的にkotlin.String型でない変数をレシーバーとしてtoString()が暗黙的に呼ばれ[4]kotlin.String型同士の演算となる。

二重引用符と一重引用符[編集]

println("出したい文字") などの文字列をくくる引用符は、kotlinでは二重引用符(ダブル クォーテーション、")のみが使用できる。 Javaと同じく、"a"aという中身のkotlin.String型のインスタンスとして認識されるが、'a'aという中身のkotlin.Char型のインスタンスとして認識される。

テンプレートリテラル[編集]

kotlinではプラス記号+で文字列を連結しなくても、下記のように文字列中に別の式を埋め込む事が出来る。

コード例
fun main() {
    
    var kazu : Int
    kazu = 5
    println("数字は $kazu だ") // (1)
        
}


実行結果
数字は 5 だ
解説

Kotlinではドル記号$をつけて変数名を文字列の中に直接書くことができる。 このことを、テンプレート・リテラルと言う。JavaScriptでも同様の機能が同じく「テンプレート・リテラル」と呼ばれる。

なお、(1) は回りくどく書くと以下のような意味になる。

println("数字は" + kazu + "だ")
// あるいは
println("数字は" + kazu.toString() + "だ")

ドル記号をエスケープする [編集]

$そのものを文字表示したい場合は、\$kazuのように、バックスラッシュ「\」をドル記号の前につけると、直後の文字を単なる文字として認識する。 これをエスケープ・シーケンスという。C言語など多くの言語に、類似の仕組みが存在する。(なお、Windows日本語版の場合、バージョンによってはバックスラッシュが円通貨マークで表示される場合もある。)

コード例
fun main() {    
    var kazu : Int
    kazu = 5
        
    println("\$kazu は $kazu だ")
}


実行結果
$kazu は 5 だ

標準入力[編集]

コンソール、ターミナル、DOSプロンプトなどから入ってくるデータをstdin、またはw:標準入力と呼ぶ。 ヒューマンフレンドリに言うならば、それらのウィンドウに入力した文字列やパイプで流した文字列を標準入力と呼ぶ。

Kotlin で同じことを行うためには、readLine() 関数を使う。

コード例
fun main() {    
    println("文字を入力してください")
    var nyuuryoku = readLine()
    println(nyuuryoku + "とあなたは入力しました")
}


実行結果の例
※ 入力内容によって結果が異なる。下記は hhh と入力した例。
文字を入力してください
hhh
hhhとあなたは入力しました


なお、Javaでは、以下のようにボイラーコードを都度書く必要があった:

// Java の場合

Scanner hensuu = new Scanner(System.in); 
String hensuu = hensuu.nextLine();

これはjava.util.ScannerにJavaでいう標準入力System.inを読みこむソースとして渡し、変数lineに標準入力の1行を格納するコードである。

条件分岐[編集]

whenを使って条件分岐をすることができる。 C言語でいうswitch case 文と似ているが、whenはbreakが必要ない。(詳しくは後述)

コード例
fun main() {
    val mes = "aa"
    
    when (mes) {
        "a" -> {
            println("mesはa")              
        }
        
        "b" -> println("mesはb")
        "c", "d", "e" -> println("mesはcかdかe")
        else -> println("mesはそれ以外")
    }
    
}


実行結果
mesはa


解説

Kotlinの場合は処理が複数行に渡る場合は中括弧 {...}を必須とすることで、JavaやC言語に見られる曖昧さを解消している。

分岐のコードについては以下の書式が許されている:

値 -> その値のときに行う処理
値 -> { その値のときに行う処理 }
値1, 値2, ... -> それらの値のときに行う処理
値1, 値2, ... -> { それらの値のときに行う処理 }

中括弧を用いるパターン {...}では、任意行の処理を書くことが許される。

when (mes){
        "a" -> {
            println("mesはa")              
        }

というのは、変数 mes が 文字列"a"なら、 -> のあとのブロックの処理をするという意味である。

なので、"b" -> println("mesはb")については、そもそもmes は"xxx"ではないので(mes は "xxx"ではなく "aa" である。)、まったく文字列「テスト」の表示は行われないのである。

kotlin の when文における 記号 -> は、単なる記号である。

C言語では、メンバアクセス演算子が (見た目の上では) 同じであるが、Cのそれは構造体のメンバにアクセスするための演算子であるため意味が全く異なる。


参考

Javaのswitch-case 文では以下のようになる:

switch (mes) {
  case "a":
    System.out.println("mesはa");
    break;
  case "b":
    System.out.println("mesはb");
    break;
  case "c": // 意図したフォール・スルー
  case "d": // 意図したフォール・スルー
  case "e":
    System.out.println("mesはcかdかe");
    break;
  default:
    System.out.println("mesはその他");
}

ここでうっかりbreakを忘れると、意図しないラベルへ処理が移ってしまう。ラベルから別のラベルへ実行が移ることををw:fall-through(フォール・スルー)と呼び、意図したものかそうでないのか判別が難しい。 なお、Go言語には、switch という命令があるが、仕様がC言語のswitchとは違っており、Go言語のswitchは標準設定ではフォール・スルーをしないようになっている。

繰り返し処理[編集]

for文と整数範囲型[編集]

for文はKotlinにも存在する。しかし、C言語とは記法を異にする。

for (変数 in 範囲)

という記法である。

たとえば

for (i in 1..5)

と書いたら、変数iを1から5まで1ずつ増やすという意味である。

変数にvarやvalを使うことはできない。(varやval などを書いても、コンパイル時にエラーになる。 )再代入もできない。

なお、型を明示して

for (i: Int in 1..5)

のように宣言してもよい。(※ 2020年6月に Fedora 32上 の kotlin 1.3.72 で、 確認。)


コード例
fun main() {
    for (i in 1..5) {
      println("for文を実行中... " + i + " of 5")
    }
}


実行結果
for文を実行中... 1 of 5
for文を実行中... 2 of 5
for文を実行中... 3 of 5
for文を実行中... 4 of 5
for文を実行中... 5 of 5
備考

Kotlinにはkotlin.ranges.IntRangeというkotlin.Int型の閉区間を表現するクラスが存在する。[5] さらに、kotlin.ranges.CharRangeというkotlin.Char型の閉区間を表現するクラスも存在する。[6] IntRange1..5のように生成するが、CharRange'A'..'D'のように生成する。

コード例
fun main() {
       
    var m = 'G'    
    if (m in 'A'..'E') {
        println("AからD")    
    }
    if (m in 'F'..'K') {
       println("FからK")    
    }
          
}


実行結果
FからK
解説
m in 'A'..'E'

というコードは、以下のコードと同一の意味である:[7]

('A'..'E').contains(m)

最内スコープ優先の法則[編集]

Kotlinでは 内側のスコープの変数と外側のスコープの変数が名前でダブった場合、内側のスコープの変数が優先される。

コード例
fun main() {
    
    var i =10
    
    for (i in 1..3) // ループ変数iは上のiとは異なる。ループ変数iはforの中でしか見えない
    {
      println("カレーライス")
      println("for内でいまiは" + i)
    }
    
    println("for終わり、いまiはいくつかな" + i)
}


実行結果
カレーライス
for内でいまiは1
カレーライス
for内でいまiは2
カレーライス
for内でいまiは3
for終わり、いまiはいくつかな10

for文のブロック内の最後では、iは3であったが、ブロックを抜けた際に、それは破棄された。そのため、ブロック外で最初にiに代入していた「10」が、最後のprintlnの表示結果として出てきていることに注目しよう。

Kotlinは、このような変数名のダブリを危険であるとして警告する。

上記コードの場合、コンパイル時に警告文として

test.kt:5:10: warning: name shadowed: i
    for (i in 1..3)
         ^

というような警告が出る。(※ 2020年6月に Fedora 32上 の kotlin 1.3.72 で、 確認。)


なお、下記のように書き換えれば、警告はでなくなる。下記コードの表示結果は上と同じである。ただし、下記のコードはウソをついている(「いまiは」と言っているのに、変数名に「i」を使用していない)。上コードとの比較のため、表示文を上コードと同じままにしている。

コード例
fun main() {
    
    var i =10
    
    for (temp in 1..3) // ループ変数名を「i」から別の変数に変更
    {
      println("カレーライス")
      println("for内でいまiは" + temp)
    }
    
    println("for終わり、いまiはいくつかな" + i)
}


注釈[編集]

  1. ^ Kotlin 1.3以降: クラスの中に存在しないmain関数はargs変数を宣言しなくても良い。

出典[編集]

  1. ^ https://jp.techcrunch.com/2019/05/08/2019-05-07-kotlin-is-now-googles-preferred-language-for-android-app-development/
  2. ^ https://kotlinlang.org/docs/reference/whatsnew13.html
  3. ^ 3.0 3.1 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/println.html
  4. ^ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to-string.html
  5. ^ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/-int-range/
  6. ^ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/-char-range/
  7. ^ https://kotlinlang.org/docs/reference/operator-overloading.html