Kotlinの雰囲気を掴む

# 概要
Kotlinを始めたので学んだことを記載していきます。
「Javaをそこそこ書いた事ある人が、この記事を読んだらざっくりKotlinを読み書きできるようになる」
これをこの記事の目標とします。
あまり深く掘り下げず、初歩的な文法を簡潔に書きたいと思います。
随時更新予定です。

# Hello World

```kotlin:Test.kt
fun main(args: Array<String>) {
    println("Hello World")
}
```

```:結果
Hello World
```

println("Hello World")の末尾に「;」がつきません。

# 変数

・基本型
　var 変数名 : 型名 = 初期値

```kotlin:Test.kt
fun main(args: Array<String>) {
    var aaa: Int = 1
    println(aaa)
}
```

```:結果
1
```

・読み出し専用(read-only)
　val 変数名 : 型名 = 初期値
　1度代入したらそれ以降の代入は基本的に不可能です。

```kotlin:Test.kt
fun main(args: Array<String>) {
    val bbb: Int = 2
    println(bbb)
}
```

```:結果
2
```

・型推論(type inference)
　var 変数名 = 初期値
　val 変数名 = 初期値
　宣言時に値が代入される変数は型定義を省略できます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    var aaa = 1
    val bbb = 2
    println(aaa)
    println(bbb)
}
```

```:結果
1
2
```

・プリミティブ型と参照型
　Kotlinには参照型しかないです。
　プリミティブ型が使える場合は、Javaのバイトコード変換時にはプリミティブ型を使います。

# 定数

・基本型
　const val 定数名 = 初期値
　どの関数からも外側に定義します。

・定数にできる型

| 型 |
|:-----:|
| Boolean |
| Byte |
| Char |
| Short |
| Int |
| Long |
| Float |
| Double |
| String |

```kotlin:Test.kt
const val CCC = 3

fun main(args: Array<String>) {
    println(CCC)
}
```

```:結果
3
```

# 範囲
　最初の値..最後の値
　in 値が範囲に含まれているか調べるキーワード
　(条件文がソースコードに出てきちゃってますが、ご了承下さい。すぐ下に条件文の説明あります。)

```kotlin:Test.kt
fun main(args: Array<String>) {
    // ランダムな値を生成(0〜5)
    val rand = (0..5).random()
    println(rand)

    if (rand in 0..2) {
        println("0〜2")
    } else {
        println("それ以外")
    }
}
```

```:結果
1
0〜2
```

※ランダム要素があるので、結果が変わる事があります。

# 条件文

・if / else
　if (条件) {
　　// 条件が真の時
　} else {
　　// 条件が偽の時
　}
　ネストも可能です。

```kotlin:Test.kt
fun main(args: Array<String>) {
    // ランダムな値を生成(0〜5)
    val rand = (0..5).random()
    println(rand)

    if (rand == 0) {
        println("0の場合")
    } else if (rand <= 3) {
        println("3以下")
    } else {
        println("それ以外")
    }
}
```

```:結果
1
3以下
```

※ランダム要素があるので、結果が変わる事があります。

・when
　返された値 = when () {
　　条件 -> 返す値
　　else -> 返す値
　}

```kotlin:Test.kt
fun main(args: Array<String>) {
    // ランダムな値を生成(0〜5)
    val rand = (0..5).random()
    println(rand)

    val result = when (rand) {
        5 -> "5の場合"
        in 2..4 ->
            if (rand == 2) {
                "2の場合"
            } else {
                "3or4"
            }
        else -> "それ以外"
    }
    println(result)
}
```

```:結果
0
それ以外
```

※ランダム要素があるので、結果が変わる事があります。
whenは初めて見るのでバイトコードに変換後、更にJavaコードに変換してみます。

```java:Test.java
public final class GameKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      byte var2 = 0;
      IntRange var5 = new IntRange(var2, 5);
      boolean var3 = false;
      int rand = RangesKt.random(var5, (Random)Random.Default);
      boolean var6 = false;
      System.out.println(rand);
      String var10000;
      if (rand == 5) {
         var10000 = "5の場合";
      } else {
         label18: {
            if (2 <= rand) {
               if (4 >= rand) {
                  var10000 = rand == 2 ? "2の場合" : "3or4";
                  break label18;
               }
            }

            var10000 = "それ以外";
         }
      }

      String result = var10000;
      var3 = false;
      System.out.println(result);
   }
}
```

if / else に書き換えたKotlinコードもバイトコード変換後、更にJavaコードに変換してみます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    // ランダムな値を生成(0〜5)
    val rand = (0..5).random()
    println(rand)

    var result = ""
    if (rand == 5) {
        result = "5の場合"
    } else if (rand in 2..4) {
        if (rand == 2) {
            result = "2の場合"
        } else {
            result = "3or4"
        }
    } else {
        result = "それ以外"
    }
    println(result)
}
```

```:結果
0
それ以外
```

※ランダム要素があるので、結果が変わる事があります。

```java:Test.java
public final class GameKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      byte var2 = 0;
      IntRange var4 = new IntRange(var2, 5);
      boolean var3 = false;
      int rand = RangesKt.random(var4, (Random)Random.Default);
      boolean var5 = false;
      System.out.println(rand);
      String result = "";
      if (rand == 5) {
         result = "5の場合";
      } else {
         label18: {
            if (2 <= rand) {
               if (4 >= rand) {
                  if (rand == 2) {
                     result = "2の場合";
                  } else {
                     result = "3or4";
                  }
                  break label18;
               }
            }

            result = "それ以外";
         }
      }

      var3 = false;
      System.out.println(result);
   }
}
```

内部的には if / else と同じように処理されるようですね。

# 演算子

・比較演算子

| 演算子 | 説明 |
|:-----:|:-- |
| <     | 左辺の値が右辺の値より小さいか？ |
| <=    | 左辺の値が右辺の値以下か？ |
| >     | 左片の値が右辺の値より大きいか？ |
| >=    | 左片の値が右辺の値以上か？ |
| ==    | 左辺の値と右辺の値が等しいか？ |
| !=    | 左辺の値と右辺の値が異なるか？ |
| ===   | 左辺のインスタンスと右辺のインスタンスの参照が等しいか？  | 
| !==   | 左辺のインスタンスと右辺のインスタンスの参照が異なるか？  | 

・論理演算子

| 演算子 | 説明 |
|:-----:|:--|
| && | 左辺と右辺の両方が真の時のみ真となる(それ以外は偽) |
| &#124;&#124; | 左辺と右辺の両方が偽の時のみ偽となる(それ以外は真) |
| ! | 真は偽となり、偽は真となる|

# 関数

・関数ヘッダー
　可視性修飾子 関数宣言キーワード 関数名(関数パラメータ): 戻り値の型
　private fun aaaBbb(ccc: Int, ddd: Int): String

・関数の例

```kotlin:Test.kt
fun main(args: Array<String>) {
    println(exFunc(0, 5))
}

private fun exFunc(firstNum: Int, lastNum: Int): String {
    val rand = (firstNum..lastNum).random()
    return rand.toString();
}
```

```:結果
0
```

※ランダム要素があるので、結果が変わる事があります。

・単一式関数
　ただ1つの式を持つだけの関数の定義に必要なコードを省略できる仕組みです。
　関数本体を書く代わりに = に続けて式を書きます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    exFunc()
}

private fun exFunc() = println("Hello")
```

```:結果
Hello
```


```kotlin:Test.kt
fun main(args: Array<String>) {
    exFunc(false)
}

private fun exFunc(aaa: Boolean) =
    if (aaa) {
        println("Hello")
    } else {
        println("World")
    }
```

```:結果
World
```

・Unit関数
　戻り値の型がUnit
　値を返さず、returnもないです。 (returnがない関数は暗黙的にUnit関数となります。)
　voidのように何も返さないというのはジェネリクスに対応出来ない等の問題があるので、
　KotlinではUnitという型を返します。

```kotlin:Test.kt
fun main(args: Array<String>) {
    exFunc()
}

private fun exFunc(): Unit {
    println("Hello")
}
```

```:結果
Hello
```

　: Unit の部分は省略できます。


・無名関数 (ラムダ)
　名前をつけずに直接定義する関数

```kotlin:Test.kt
fun main(args: Array<String>) {
    println({
        val str = "World"
        "Hello " + str
    }())
}
```

```:結果
Hello World
```

・関数型
　無名関数にも型があり、それを関数型 (function type) と呼びます。
　関数型の変数には、値として無名関数を格納でき、関数のコードの中で渡す事ができます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    val aaaBbb: () -> String = {
        val str = "World"
        "Hello " + str
    }
    println(aaaBbb())
}
```

```:結果
Hello World
```

・暗黙的な戻り値
　上の例でStringを返す無名関数なのに return がない点を疑問を感じたかもしれません。
　無名関数には基本的にreturnが不要です。 (というか return を入れると基本的にエラーが出ます。)
　コンパイラから見て、無名関数を呼び出した関数の戻り値なのか、無名関数自身の戻り値なのか曖昧になる為
　です。
　無名関数は、暗黙的に関数定義最後の行を返します。

・無名関数の引数
　val 関数型の変数名: (引数の型) -> 戻り値の型 = { 引数名 -> 無名関数の本体 }

```kotlin:Test.kt
fun main(args: Array<String>) {
    val aaaBbb: (String) -> String = { ccc ->
        "Hello " + ccc
    }
    println(aaaBbb("World"))
}
```

```:結果
Hello World
```

・it
　1つだけ引数を受け取る無名関数を定義する時には、その引数名の代わりに it が使えます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    val aaaBbb: (String) -> String = {
        "Hello " + it
    }
    println(aaaBbb("World"))
}
```

```:結果
Hello World
```

・複数の引数

```kotlin:Test.kt
fun main(args: Array<String>) {
    val aaaBbb: (String, String) -> String = { ccc, ddd ->
         ccc + " " + ddd
    }
    println(aaaBbb("Hello", "World"))
}
```

```:結果
Hello World
```

・関数型の型推論
　変数と同様に関数型でも型推論されます。

```kotlin:Test.kt
fun main(args: Array<String>) {
 // val aaaBbb: (String, String) -> String = { ccc, ddd ->
    val aaaBbb = { ccc: String, ddd: String ->
         ccc + " " + ddd
    }
    println(aaaBbb("Hello", "World"))
}
```

```:結果
Hello World
```

　※戻り値の String が型推論されています。

・関数を受け取る関数

```kotlin:Test.kt
fun main(args: Array<String>) {
    val func = { aaa: String, bbb: String -> String
        aaa + " " + bbb
    }
    exFunc("Hello", func)
}

fun exFunc(ccc: String, dddEee: (String, String) -> String) {
    println(dddEee(ccc, "World"))
}
```

```:結果
Hello World
```

・最後の引数が関数型の時の略記
　関数以外の引数を () に入れて渡し、最後の引数を () の外に書けます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    exFunc("Hello") { aaa, bbb ->
        aaa + " " + bbb
    }
}

fun exFunc(ccc: String, dddEee: (String, String) -> String) {
    println(dddEee(ccc, "World"))
}
```

```:結果
Hello World
```

・関数リファレンス
　名前付きの関数も引数として渡す事ができます。
　:: の後にリファレンスを得たい関数名を書きます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    exFunc1("Hello", ::exFunc2)
}

fun exFunc1(aaa: String, bbb: (String) -> Unit)
{
    bbb(aaa + " ");
}

fun exFunc2(ccc: String) {
    println(ccc +  "World")
}
```

```:結果
Hello World
```

・戻り値の型としての関数型
　関数を返す関数を定義する事ができます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    exFunc1()
}

fun exFunc1()
{
    val aaa =  exFunc2()
    println(aaa("Hello"))
}

fun exFunc2(): (String) -> String {
    val space = " "
    return { bbb: String ->
        bbb + space + "World"
    }
}
```

```:結果
Hello World
```

　この場合、exFunc2 の戻り値の型は (String) -> String となります。
　
　因みに、Kotlin の無名関数 (ラムダ) はクロージャです。
　(クロージャの説明については、本筋から外れるので省略とさせて下さい。)

# null 許容度
Kotlin には null の値を代入できる null 許容型と null 非許容型があります。

・null 非許容型

```kotlin:Test.kt
fun main(args: Array<String>)
{
    var aaa = "str"
    // ここが原因でコンパイルできません
    aaa = null
    println(aaa)
}
```

String は null 非許容型の為、null を代入する事ができません。

・null 許容型
　? をつけます。
　String?

```kotlin:Test.kt
fun main(args: Array<String>) {
    var aaa = exFunc()
    println(aaa)
}

fun exFunc() : String? {
    return "str"
}
```

```:結果
str
```

aaa は String? 型なので null を代入する事ができます。

```kotlin:Test.kt
fun main(args: Array<String>) {
    var aaa = exFunc()
    // nullを代入する事ができます
    aaa = null
    println(aaa)
}

fun exFunc() : String? {
    return "str"
}
```

```:結果
null
```

・セーフコール演算子

```kotlin:Test.kt
fun main(args: Array<String>) {
    // exFuncがnullになる事がある為、capitalizeを呼ぶ事ができません
    // コンパイルできません
    var aaa = exFunc().capitalize()
    println(aaa)
}

fun exFunc() : String? {
    return "str"
}
```

セーフコール演算子 ? を追加する事で capitalize を呼び出す事ができるようになります。

```kotlin:Test.kt
fun main(args: Array<String>) {
    var aaa = exFunc()?.capitalize()
    println(aaa)
}

fun exFunc() : String? {
    return "str"
}
```

```:結果
Str
```

exFunc が null を返してきた場合 capitalize は呼ばれません。