Kotlin の基礎を学ぶなら Kotlin Playground で 🏕️

最終更新日

Kotlin を web で試せる遊び場

play.kotlinlang.org で Kotlin を実行して遊ぼう!コードエディタ (画面上部) と標準出力 (画面下部) だけのシンプルな構成だから、とっつきやすいのも良いところ。Android アプリ開発で必要な Kotlin 基礎を学ぶのにぴったりだ。

Haskell にも似た遊び場がある (play.haskell.org)。こういうのってクールだよね😎

初心者向けの Android 公式チュートリアルをやってみた

developer.android.com/courses には 3 つの研修教材がある。[初心者向け]、[経験豊富な Android デベロッパー向け]、そして [認定資格プログラム]。このうち [初心者向け] に提供されている [Compose を用いた Android アプリ開発の基礎] は、8 つのユニットで構成される教材だ。

この記事では、ユニット 2 [アプリ UI を作成する] に含まれる 3 つのパスウェイのうち、最初の 1 つ [Kotlin の基礎] の学びと感想をメモする。ユニット 1 をやったのは 4 ヶ月も前 (2024 年 9 月) で、その内容はすでに忘れかけてる…😅

ユニット 2 [ユニット 2: アプリ UI を作成する] に含まれる 3 つのパスウェイ

以下では、[アクティビティ 2] から [アクティビティ 5] について感想を書く。[ユニット 2] > [パスウェイ 1] は、[アクティビティ 1] から [アクティビティ 7] までの計 7 つを含むけど、1、6、7 は教材じゃないのでね (1 は導入、6 は問題集、7 はまとめ)。

2 Kotlin で条件を記述する

[Kotlin で条件を記述する] では、ifwhen を学ぶ。また条件の記述に x in 0..10 のような記法が使えることも学ぶ。後者は僕にとって新しかったけど、その他はかなり基本的な内容だから簡単だった。

3 Kotlin で null 可能性を使用する

[Kotlin で null 可能性を使用する] では、nullable な変数を学ぶ。nullable な変数を宣言するには var x: Int? のように書く。これは「整数型であり、値に null を許容する変数 x を宣言する」という意味 (のはず)。例えばこんなふうに使う。

fun main() {
    val x: String? = null

    println("Length of 'x' is ${x?.length ?: 0}")
}

// 出力
Length of 'x' is 0

nullable な変数の property や method にアクセスする際は、. ではなくセーフコール演算子 ?. を使う。JavaScript のオプショナルチェーンを見たことがあるから、連想で理解した。セーフコール演算子 ?. の結果が null のとき、エルヴィス演算子 ?: を使ってフォールバック値を設定できる。

4 Kotlin でクラスをオブジェクトを使用する

class の field を constructor で指定するには class MyClass(var myField: String) {} のように書く。OOP の概念はざっくり浅く理解してるつもりだけど、それをコードで表現するのは初めてだから手こずった。[Kotlin でクラスとオブジェクトを使用する] の、僕の理解度は怪しい🫠

コンパイラは、primary と secondary のいずれの constructor が呼び出されたかを、呼び出し側が渡す引数の型と個数で判別するらしい。したがって、primary と同じ型の引数を同じ数だけ受け取る secondary constructor を作ることはできない (はず)。これ教材に書いてなかった気がする。

class SmartDevice(val name: String, val category: String) {
    var deviceStatus = "online"

    constructor(name: String, category: String, statusCode: Int) : this(name, category) {
        deviceStatus = when (statusCode) {
            0 -> "offline"
            1 -> "online"
            else -> "unknown"
        }
    }
    ...
}

// primary constructor を呼び出すならこう
val myDevice1 = SmartDevice(name = "Pixel", category = "High-end")

// secondary constructor を呼び出すならこう
val myDevice2 = SmartDevice(name = "iPhone", category = "Middle-calss", statusCode = 0)

親を継承した子 class を定義するには、class SubClass(val param2: Int) : SuperClass(val param1: Int) {} のように書く。

下の表は、可視性修飾子の端的なまとめ。僕はまだ小さいプログラムしか作ってないから、有り難みの実感がない。

修飾子同じクラスでアクセス可能サブクラスでアクセス可能同じモジュールでアクセス可能モジュール外からアクセス可能
private
protected
internal
public
Kotlin でクラスとオブジェクトを使用する

移譲 class (インタフェース?) の実装を実践したけど、実は全然分かってない。class MyInterface() : ReadWriteProperty<Any?, Int> {} を見れば、ReadWriteProperty 型の class を定義したことは分かる。それで、<Any?, Int> は何?教材は「気にしないでください」と言ってるので、そのうち解説されるのかな…?

5 Kotlin で関数型とラムダ式を使用する

[Kotlin で関数型とラムダ式を使用する] は楽しい。関数を変数に代入する方法が 2 つ紹介されてた。

  • 関数 fun myFunction を変数 val x に代入するには、val x = ::myFunction と書く
  • Lambda 式 {} を使用して、val x = { ... function body ... } と書く。
    • Lambda 式では、最後の行がその返り値となる (と思う。教材に明示的に書かれてない)
    • 最後の行が式なら、それが返り値
    • 最後の行が文なら、返り値は Unit (返り値なし)

Lambda 式では、-> の前に引数の変数名を定義する。1 行目の最後の quantity がそれ。

val coins: (Int) -> String = { quantity ->
    "$quantity quarters"
}

(上の例のように) 取る引数が 1 つだけの場合、引数を入れる変数の名前を省略できる。省略した場合は、関数本体で変数 it として呼び出せる。

val coins: (Int) -> String = {
    "$it quarters"
}

関数にも型がある。関数の型は (Int) -> String のように書いて、「Int を受け取って String を返す関数型」と読む。変数名は書かず、入出力の型のみを書くのがポイント。そりゃそうだよね、型を記述するために、入出力の変数名まで指定する必要が無い。

fun trickOrTreat(
    isTrick: Boolean, 
    extraTreat: (Int) -> String
): () -> Unit {
    //... function body ...
}

例えば上のように定義される関数 trickOrTreat は、「引数に isTrickextraTreat を取り、() -> Unit 型の関数を返す関数」だ。isTrickBoolean (分かりやすい) で、extraTreat(Int) -> String 型の関数だ。

関数型を引数に取る関数に対し、Lambda 式を直接渡すことができる。例えば上の関数 trickOrTreat() に渡す引数 extraTreat を、下のようにインラインで定義できる。Lambda 式 { "$it quarters" } の型は (Int) -> String なので、関数 trickOrTreat() の引数の型に合う。

val treatFunction = trickOrTreat(false, { "$it quarters" })

🤔 Lambda 式 { "$it quarters" } の型は、この定義だけを見ても分からない (はず)。分かるのは (型不明の 1 つの引数) -> String 型であるということ。この Lambda 式を受け取る関数 trickOrTreat() の引数の定義を見て、これが (Int) -> String 型だと判明する (のだと思う)。

そして最重要なのが、後置 Lambda 構文だ。ある関数の最後の引数が関数のとき、引数を渡す括弧の外に Lambda 式を書いて、その関数の「関数を取る引数」に関数を渡せる。例えば上の関数 trickOrTreat() でも後置 Lambda 構文が使える。

val treatFunction = trickOrTreat(false) { "$it quarters" }

何が嬉しいのかまだしっかりと理解してないけど、おそらく利点は「読みやすい」だろう。例えば上の trickOrTreat(false) { "$it quarters" } は、普通の関数定義のようにも見えるよね (僕はまだ見慣れてないので it が唐突に感じるけど)。

コメントを残す

回れ右の内輪差をもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む