LoginSignup
4
2

More than 5 years have passed since last update.

Kotlinのチュートリアルをやってみた③

Posted at

前回に引き続きSwiftエンジニアがKotlinのチュートリアルを進めます。今回はBasic syntax walk-throughの章です。
http://try.kotlinlang.org/#/Examples/Basic%20syntax%20walk-through/Use%20a%20conditional%20expression/Use%20a%20conditional%20expression.kt

自分が実装した分のリポジトリ

https://github.com/akatsuki174/KotlinTutorial
上記のBasicSyntaxWalkThrough.ktファイル

Basic syntax walk-through

Use a conditional expression

ここではifの使い方と関数の使い方が学べます。

fun max(a: Int, b: Int) = if (a > b) a else b

ifに関しては前回の記事にも書いたので省略します。関数についてですが、以下のことについては今までのチュートリアルでも学んだことです。

  • 関数宣言はfunであること
  • selfなどなしに呼び出せること

今回はそれに加え単一式関数の記法が出てきました。単一の値を返すだけであれば=で繋いで1行で書くことができます。また、型推論ができる場合には戻り値の型を指定する必要はありません。ということで、以下のような書き方も可能です。

// 戻り値の型を指定
fun max(a: Int, b: Int):Int = if (a > b) a else b

// ブロックを使用
fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

引数については名前:タイプの順で書かれること、引数を複数持つ場合はカンマで区切るということがわかります。また、Javaとは異なり名前付き引数を使うこともできます。今回の例の場合だと、次のように書くことができます。

max(a = args[0].toInt(), b = args[1].toInt())

ifに関しての公式資料はこちら
単一式関数に関しての公式資料はこちら

Null-checks

fun main(args: Array<String>) {
    if (args.size < 2) {
        println("No number supplied");
    } else {
        val x = parseInt(args[0])
        val y = parseInt(args[1])

        // x,yにnullが入っている可能性がある
        if (x != null && y != null) {
            print(x * y)
        } else {
            println("One of the arguments is null")
        }
    }
}

// もしstrが数字ではなかったらnullを返す
fun parseInt(str: String): Int? {
    try {
        return str.toInt()
    } catch (e: NumberFormatException) {
        println("One of the arguments isn't Int")
    }
    return null
}

JavaではnullオブジェクトにアクセスするとNullPointerExceptionが発生していました。KotlinはコードからNullPointerExceptionが発生しないように作られています。NullPointerExceptionが発生するのは以下の状態の時です。

  • 明示的にthrow NullPointerException()をした時
  • 一定条件下で!!を使った時
  • 外部のJavaコードがNullPointerExceptionになった時
  • 初期化の際のデータ不備(初期化されていないのにどこかで使われている)

Swiftのように、ある変数がnullになりうる場合は「?」を付けてそれを明示しなければなりません。
「安全でない」場合は以下のような表示が出ます。
スクリーンショット 2017-04-16 10.03.05.png

null安全に関する公式資料はこちら

is-checks and smart casts

fun main(args: Array<String>) {
    println(getStringLength("aaa"))
    println(getStringLength(1))
}

fun getStringLength(obj: Any): Int? {
    if (obj is String)
        return obj.length // no cast to String is needed
    return null
}

isは型チェックを行うことができ、否定型は!isになります。

isで型チェックを行うと自動的にキャストが行われるため、上の例でもobjは型チェック後すぐにString型として使えています。公式に例として載っている以下のコードはとてもクールだと思います。

if (x !is String) return
print(x.length) // x is automatically cast to String

また以下のようなコードも書けます。型チェック後すぐにString型として使うことができています。

if (x !is String || x.length == 0) return

whenとの組み合わせでも使われます。

when (x) {
  is Int -> print(x + 1)
}

クラスと継承に関する公式資料はこちら
スマートキャストに関する公式資料はこちら

Use a while-loop

fun main(args: Array<String>) {
    var i = 0
    while (i < args.size)
        println(args[i++])
}

whiledo..whileの書き方を学ぶサンプルになります。do.whileで書く場合はこのような形を取ります。

do {
    println(args[i++])
} while (i < args.size)

whileループに関する公式資料はこちら

Use a for-loop

fun main(args: Array<String>) {
    for (arg in args)
        println(arg)
    println()
    for (i in args.indices)
        println(args[i])
}

今度はforループの使い方についてです。前回の記事でも書いた通り、このような書き方もできます。

for ((index, value) in args.withIndex())
    println("$index: value is $value")

forループに関する公式資料はこちら

Use ranges and in

fun main(args: Array<String>) {
    val x = args[0].toInt()
    // xがある範囲内に入っているか確認
    val y = 10
    if (x in 1..y - 1)
        println("OK")

    //範囲内で繰り返し
    for (a in 1..5)
        print("${a} ")

    println()
    val array = arrayListOf<String>()
    array.add("aaa")
    array.add("bbb")
    array.add("ccc")

    // ある数値が範囲外か確認
    if (x !in 0..array.size - 1)
        println("Out: array has only ${array.size} elements. x = ${x}")

    // コレクションがあるオブジェクトを含むか確認
    if ("aaa" in array) // collection.contains(obj) is called
        println("Yes: array contains aaa")
    if ("ddd" in array) // collection.contains(obj) is called
        println("Yes: array contains ddd")
    else
        println("No: array doesn't contains ddd")
}

range, inとともに使われることがある関数としてdownTostepがあり、以下のような使い方をします。

// 数を逆順に処理したければdownTo関数が使える
for (i in 5 downTo 1) print(i)
// xつごとに処理を実行したい場合はstep関数が使える
for (i in 1..4 step 2) print(i) // 2つごとに処理を実行

Rangeに関する公式資料はこちら

Use when

fun main(args: Array<String>) {
    cases("Hello")
    cases(1)
    cases(0L)
    cases(MyClass())
    cases("hello")
}

fun cases(obj: Any) {
    when (obj) {
        1 -> println("One")
        "Hello" -> println("Greeting")
        is Long -> println("Long")
        !is String -> println("Not a string")
        else -> println("Unknown")
    }
}

class MyClass() {
}

whenに関しては前回の記事でも書いたのでさらっと書きます。switch文のような形で使うことができます。条件を満たすものが現れるまで評価し続けます。isを使って型判定も行うことができます。

感想

名前付き引数があるので読みやすい

Javaとは異なり引数に名前を付けられるのは読みやすくていいなと思います。ただ引数の名前は任意であるため、IntelliJ IDEAで関数名を自動補完で入力した時に引数名も入力されないのは少し残念だなと思いました。

↓自動補完時の挙動
スクリーンショット 2017-04-22 22.34.07.png

スクリーンショット 2017-04-22 22.34.17.png

型周りが扱いやすい

↓これって結構すごいことだと思っています。

fun cases(obj: Any) {
    when (obj) {
        1 -> println("One")
        "Hello" -> println("Greeting")
        is Long -> println("Long")
        else -> println("Unknown")
    }
}

Swiftで同じように書こうとしてもできないですし(たぶん)。

スクリーンショット 2017-04-22 22.54.01.png

4
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2