拡張関数/エクステンションは、継承やクラスそのものを変更することなく、既存のクラスに新しい機能を追加することを可能にするメカニズムです。
例えば、Stringクラスに対して文字列を反転する関数を追加します:
fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"
拡張は実際にはクラスを修正するのではなく、単に構文上の糖であり、オブジェクトのインスタンスを最初のパラメータとして受け取る静的メソッドとしてコンパイルされます。
利点: 簡潔さ、可読性、コードの拡張性。コレクションや文字列などのユーティリティ関数によく適しています。
落とし穴:
拡張関数を使用して、状態を保持する新しい変数(プロパティ)をクラスに追加できますか?
回答: いいえ。Extension propertyは常に計算プロパティ(getter/setter)であり、フィールドではありません。状態を保持することはできず、オンザフライで計算することだけが可能です。
val String.secondChar: Char get() = this[1] // これは計算のみ、保持はしない!
物語
データ検証のプロジェクトで、開発者はモデルクラスに拡張プロパティを追加しましたが、それが値を保持しているかのように扱った後、値が常に計算されることに気付き、同じ呼び出しがあるとロジックが正しく動作しませんでした。
物語
大規模なアプリケーションで、拡張がクラスのメソッドと同じ名前で命名され、混乱を引き起こしました:クラスのメソッドが常に優先され、拡張が呼び出されず、「見えない」コードのデバッグに1日を費やしました。
物語
一つのライブラリで、拡張がクラスのプライベートフィールドに使用されましたが、後でプライベートにアクセスできないことが判明したため、モデルのアーキテクチャをリファクタリングする必要がありました。