Kotlinの中置関数

Kotlinの挿入関数

1. 前書き

Kotlinは、よりクリーンで読みやすいコードを作成できるように、多くの新しい機能を追加する言語です。

これにより、コードの保守が大幅に容易になり、開発の最終結果が向上します。 Infix notationはそのような機能の1つです。

2. 中置記法とは何ですか?

Kotlinでは、ピリオドと角かっこを使用せずに一部の関数を呼び出すことができます。 These are called infix methods, and their use can result in code that looks much more like a natural language.

これは、インラインMap定義で最も一般的に見られます。

map(
  1 to "one",
  2 to "two",
  3 to "three"
)

“to”は特別なキーワードのように見えるかもしれませんが、この例では、これは中置記法を利用してPair<A, B>.を返すto()メソッドです。

3. 一般的な標準ライブラリの中置関数

Pair<A, B>インスタンスの作成に使用されるto()関数とは別に、infix.として定義される他の関数がいくつかあります。

たとえば、さまざまな数値クラス(Byte,Short, Int,およびLong)はすべて、ビット単位の関数and(), or(), shl(), shr(), ushr(),およびxor(),を定義し、より読みやすい式を可能にします。

val color = 0x123456
val red = (color and 0xff0000) shr 16
val green = (color and 0x00ff00) shr 8
val blue = (color and 0x0000ff) shr 0

Booleanクラスは、同様の方法でand(), or()およびxor()論理関数を定義します。

if ((targetUser.isEnabled and !targetUser.isBlocked) or currentUser.admin) {
    // Do something if the current user is an Admin, or the target user is active
}

Stringクラスは、match関数とzip関数も中置辞として定義し、読みやすいコードをいくつか許可します。

"Hello, World" matches "^Hello".toRegex()

標準ライブラリには他にもいくつかの例がありますが、これらはおそらく最も一般的なものです。

4. カスタム中置メソッドの記述

多くの場合、独自の中置メソッドを作成したいと思うでしょう。 These can be especially useful, for example, when writing a Domain Specific Language for our application、DSLコードをはるかに読みやすくします。

いくつかのKotlinライブラリは、すでにこれを非常に効果的に使用しています。

たとえば、mockito-kotlinライブラリは、モック動作を定義するときに使用するいくつかの中置関数(doAnswerdoReturn,、およびdoThrow —)を定義します。

中置関数の記述は、次の3つのルールの単純なケースです。

  1. この関数は、classで定義されているか、classの拡張メソッドです。

  2. この関数はパラメーターを1つだけ取ります

  3. 関数はinfixキーワードを使用して定義されます

簡単な例として、テストで使用するための簡単なAssertionフレームワークを定義しましょう。 中置関数を使用して、左から右に適切に読み取る式を許可します。

class Assertion(private val target: T) {
    infix fun isEqualTo(other: T) {
        Assert.assertEquals(other, target)
    }

    infix fun isDifferentFrom(other: T) {
        Assert.assertNotEquals(other, target)
    }
}

This looks simple and doesn’t seem any different from any other Kotlin code。 ただし、infixキーワードが存在すると、次のようなコードを記述できます。

val result = Assertion(5)

result isEqualTo 5 // This passes
result isEqualTo 6 // This fails the assertion
result isDifferentFrom 5 // This also fails the assertion

すぐに、これは読みやすくなり、理解しやすくなります。

Note that infix functions can also be written as extension methods to existing classes。 これは、標準ライブラリを含む他の場所からの既存のクラスをニーズに合わせて拡張できるため、強力です。

たとえば、Stringに関数を追加して、特定の正規表現に一致するすべての部分文字列を引き出しましょう。

infix fun String.substringMatches(r: Regex) : List {
    return r.findAll(this)
      .map { it.value }
      .toList()
}

val matches = "a bc def" substringMatches ".*? ".toRegex()
Assert.assertEquals(listOf("a ", "bc "), matches)

5. 概要

このクイックチュートリアルでは、既存の関数を使用する方法や、コードをよりクリーンで読みやすくするために独自の関数を作成する方法など、挿入関数で実行できることを示します。

いつものように、コードスニペットはover on GitHubにあります。