Kotlinの基本文法① ～型・変数宣言～

## 基本型

```kotlin
// 文字列
val kata1: String = ""
// 数値 (32ビットまで)
val kata2: Int = 0
// 数値 (64ビットまで)
val kata3: Long = 1000000000000000000
// 真偽地
val kata4: Boolean = true
// 単一文字 (シングルクォートで囲む)
val kata5: Char = '1'
// 小数 (32ビットまで)
val kata6: Float = 1.5F
// 小数 (64ビットまで)
val kata7: Double = 1.5555555555555555555555
// 要素の操作を行えないリスト
val kata8: List<String> = listOf("a", "b", "c")
``` 

## 文字列型

* 文字列テンプレート

```kotlin
val age: String = "28"
val temp1: String = "私は${age}歳です" // → 私は28歳です
// 計算も可能
val temp2: String = "私は${age + 10 * 5}歳です"
```

* 文字列の比較

```kotlin
// 文字列型の比較は "=="でOK
val name1: String = "taro"
val name2: String = "taro"

if(name1 == name2) print(true) else print("false") // → true
```

* 改行入り文字列

```kotlin
val a = """
  |Hello \n
  |World
  """.trimMargin()

// trimMargin()は「|」を取り除き文字列展開する。エスケープ不要
```

* 文字列をコレクションとして扱う 

```kotlin
val helloWorld: String  = "hello world"
println(helloWorld[4]) // → o
```

## Any型

* Any型は全ての親クラス。型が不明なクラスを扱う時、Any型を付与することで型チェックを無効にし、コンパイルを通すことができるが、Kotlinの型安全の恩恵を受けることができないため、Any型は使用しないことが望ましい

```kotlin
var anyType: Any = 1
anyType = "any"
anyType = 1.55

// 実行するとコンパイルエラーにならず、最後に代入したDouble型の値が出力される。
print(anyType.toString() + " " + anyType.javaClass)
```

## Nothing型
* Nothing型は全てのサブクラス。またNothing型は存在しない値を表し、完了しないことを意味する。値が返されないため、例外をスローする際等に利用される。

```kotlin
val exception: Nothing = throw RuntimeException("throew RuntimeException!!")
throw exception
```

## Unit型

* Unit型は型がないことを表す。一般的には値を返さない関数の戻り値として利用する。関数宣言「fun unitType() {}」は「fun unitType(): Unit {}」を省略した記述。

```kotlin
fun unitType(): Unit {
    return Unit
}

// ↑の関数宣言を省略したのが↓

fun unitType() {}
```

## Null許容型 

* null許容型は型の末尾「?」をつける。全てに型に対してnull許容・非許容を選択できる
* null非許容型にnullが代入されるとコンパイルエラーとなり、「NullPointerException」が発生する

```kotlin
// null非許容型
var v1 : Int = 0 
v1 = null // →nullを割り当てられない。

// null許容型
var v2: Int? = 0 
v2 = null // nullを割り当てることができる
```

* Nullの安全な呼び出し 
    * Null許容型から関数やプロパティを直接呼び出せないため、Null許容型に対してNullでないことを事前に検証する必用がある。

```kotlin
val v3: String? = "abc"
val v4: String? = null

v3.length  // → v3がnullかもしれないので、直接プロパティを呼び出せない

// v3がnullではないことを検証する
// 方法1 事前にif文で検証
if ( v3 != null) {
    v3.length
}

// 方法2 ?を連結して呼び出し (nullの場合プロパティ呼び出しを行わない
v3?.length
println("v3 = ${v3?.length}") // v3 = 3
println("v4 = ${v4?.length}") // v4 = null

// エルビス演算子「?:」はnullであれば特定の処理を呼び出す
println("v4 = ${v4?.length ?: "0"}") // v4 = 0
```

## 列挙型

* 列挙型定義

```kotlin
enum class Color {
    RED, GREEN, BLUE
}
```

* 列挙型定義（引数有）

```kotlin
enum class Subject(
    // 列挙型に値を持たせる
    private val point: Int, // privateの場合値を取得するメソッドを別に定義する必用有
    public val evaluation: String // publicの場合直接アクセス可能
) {
    MATH(93, "大変良い"),
    ENGLISH(77, "良い"),
    SCIENCE(75, "良い"); // ← 列挙型以外にメソッドを定義する場合「;」で終わらせる

    // 点数を取得
    fun getPoint() = this.point
}
```

* 変数宣言

```kotlin
// enum型宣言
val red: Color = Color.RED
val green: Color = Color.GREEN
val blue: Color = Color.BLUE
```

* 比較

```kotlin
println(red == Color.RED) // true
println(red == Color.GREEN) // false
```

* ordinal 
    * 宣言の順番を返す（0始まり）

```kotlin
println("RED ordinal ${red.ordinal}") // RED ordinal 0
println("BLUE ordinal ${blue.ordinal}") // RED ordinal 2
```

* name 
    * enum型の名前をString型で返す

```kotlin
println("RED name ${red.name}")  // "RED" 
println("GREEN name ${green.name}") // GREEN
```

* valueOf 
    * enum型の名前を引数に渡して一致する値を取得する

```kotlin
println(" valueOf  ${Color.valueOf("RED")}")
println(" valueOf  ${Color.valueOf("BLUE")}")
// 存在しない列挙型名称を渡すとIllegalArgumentExceptionが発生
```

* values
    * 列挙型の配列を返す(並びは宣言順)

```kotlin
Color.values().forEach { println(it) } // RED GREEN BLUE
```

* 列挙型の引数
    * 定義された値にアクセスする
    
```kotlin
// privateで定義されているので直接アクセス不可。別途メソッドを定義して値を呼び出す
Subject.ENGLISH.point   
println("ENGLISH point = ${Subject.ENGLISH.getPoint()}") // ENGLISH point = 77

// publicで定義されている場合は直接アクセス可能
println("ENGLISH evaluation = ${Subject.ENGLISH.evaluation}") // ENGLISH evaluation = 良い
```

## 型推論

* 変数の宣言時に明示的に型を指定しない場合、代入された値から型推論するため型宣言を省略することができる

```kotlin
val v1 = 1
println("v1 =  ${v1.javaClass.kotlin}") // v1 = class kotlin.Int

val v2 = "2"
println("v2 =  ${v2.javaClass.kotlin}") // v2 =  class kotlin.String

val v3 = listOf(1, 2)
println("v3 =  ${v3.javaClass.kotlin}") // v3 =  class java.util.Arrays$ArrayList

val v4 = mapOf( "1" to 1, "2" to 2)
println("v4 =  ${v4.javaClass.kotlin}") // v4 =  class java.util.LinkedHashMap

// 型推論により型として認識されるため、代入する型がことなる場合はコンパイルエラーが発生する
var int = 123
var double = 12.3

int = double  // ←コンパイルエラー
```



## 変数の宣言

### var

* 一度変数宣言した後に値の再代入が可能
* 値の再代入はバグが混入しやすく、テストも複雑になりやすいため可能な限り後述の`val`を使用することが望ましい


```kotlin
var countVar: Int = 0
countVar = 5
print(countVar)  // → 5
```


### val
* 一度変数宣言した後に値の再代入が不可
* 値の再代入はバグが混入しやすいことから、`val`で統一するのが望ましい

```kotlin

val countVal: Int = 0
countVar ++;  // 再代入するとコンパイルエラーが発生

```