おはようエンジニア

まともなエンジニアになりたい

『Kotlinイン・アクション』第3章を読む (その2)

Kotlinイン・アクション第3章「関数の定義と呼び出し」の続きです。

拡張関数

既存のクラスに対して外側から関数を追加する

// StringクラスにlastChar()関数を追加
// String がレシーバ型, this がレシーバオブジェクト
fun String.lastChar(): Char = this.get(this.length - 1)

// レシーバオブジェクトのメンバの呼び出しはthis省略可
fun String.lastChar(): Char = get(length - 1)
  • 拡張関数のオーバーライド
    • 拡張関数は静的メソッドとして扱われるのでオーバーライドはできない

拡張プロパティ

// StringクラスにlastCharプロパティを追加
val String.lastChar: Char
    get() = get(length - 1)

可変長引数

可変長引数は vararg 修飾子を使う

fun listOf<T>(vararg values: T): List<T> { ... }

中置呼び出し

infix 修飾子で中置呼び出しのメソッドを宣言できる

infix fun Boolean.nand(other: Boolean) = !(this and other)

println(true nand false) // -> true

ローカル関数

  • 関数内に関数を入れ子で定義できる(ローカル関数)
  • ローカル関数は外側の関数の引数や変数にアクセスできる

ローカル関数と拡張関数を使ったコードの整理

以下のように整理していくと、クラスのコードベースを抑えつつ重複を排除できる (ただし2段階以上の入れ子は読みにくくなることが多い)

  1. 関数の中から重複しているコードを見つける
  2. 重複部分をローカル関数として抽出する
  3. ロジックを拡張関数に抽出する

文字列と正規表現

splitで分割

// 必要な数だけ区切り文字を渡す
println("12.345-6.A".split(".", "-")) // -> [12, 345, 6, A]

substringに分割

// ":"より前を抽出 -> http
println("http://example.com".substringBefore(":"))
// 最後の"/"より後を抽出 -> example.com
println("http://example.com".substringAfterLast("/"))

トリプルクオート文字列

  • トリプルクオート内はエスケープ不要
  • インデントを無視するには接頭辞をつけて trimMargin を呼び出すと便利
val str = """
    |1: hoge
    |2: fuga
""".trimMargin("|")

正規表現でURLの簡易チェック

// トリプルクオート文字列でパターンを記述してRegex型に変換
val regex = """(.+)://(.+)/(.+)""".toRegex()
val matchResult = regex.matchEntire("http://example.com/hoge")
if (matchResult != null) {
    // 分割宣言で中身を取り出す
    val (scheme, host, path) = matchResult.destructured
    print("scheme: $scheme, host: $host, path: $path")
}

第3章はここまでです。