SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

【最新Kotlinアップデート解説】バージョン1.1からの変更点総まとめ

Kotlin最新アップデートまとめ ──委譲プロパティやインラインクラスに関するアップデート

【最新Kotlinアップデート解説】バージョン1.1からの変更点総まとめ 第4回

  • X ポスト
  • このエントリーをはてなブックマークに追加

委譲プロパティに関する変更点(2)

委譲プロパティはローカルプロパティでも可能

 こういった委譲プロパティは、ローカルプロパティでも可能なようにバージョン1.1で変更されています。そのため、例えば先のConnectionFactory()は、リスト5のように関数内でも利用できます。

[リスト5]ConnectionFactoryをローカルプロパティの委譲先とするコード例
val connection: Connection by ConnectionFactory()
connection.connect()

委譲先インターフェース

 リスト3では、委譲先クラスとして、通常のクラスを作成してgetValue()演算子とsetValue()演算子をオーバーライドする方法を採りました。

 一方、Kotlinの標準ライブラリには委譲先クラスを表すインターフェースとして、valプロパティの委譲先用のReadOnlyPropertyとvarプロパティの委譲先用のReadWritePropertyが用意されています。このインターフェースを実装する形で、getValue()メソッド(とsetValue()メソッド)をオーバーライドする方法も可能です。なお、getValue()メソッドとsetValue()メソッドのシグネチャは、表1と同じです。

 この仕組みは、クラスではなく、無名オブジェクトを委譲先として用意する場合に有効です。例えば、リスト6のコードです。

[リスト6]ReadOnlyPropertyを実装した無名オブジェクトを委譲先とするコード例
val connectionFactory = object : ReadOnlyProperty<Any?, Connection> {
  override fun getValue(thisRef: Any?, property: KProperty<*>): Connection {
    :
  }
}
val connectionObj: Connection by connectionFactory
connectionObj.connect()

 リスト6での注意点は、ReadOnlyPropertyとReadWritePropertyを利用する場合は、そのジェネリクスとして委譲元プロパティが所属するクラスとプロパティそのもののデータ型(表1のOwnerとV)を指定する必要があることです。リスト6では、ローカルプロパティへの委譲のため、そもそも所属先クラスがわからないのでAny?としています。

 なお、このReadWritePropertyインターフェースがReadOnlyPropertyインターフェースを継承するようにバージョン1.4で変更されています。そのため、ReadWritePropertyインターフェースを実装したクラス(オブジェクト)をvalプロパティの委譲先とできるようになっています(もちろん、その際、setValue()メソッドの実装コードは実行されずに無駄とはなってしまいますが)。

委譲先インスタンスの生成コードを記述する

 委譲プロパティに関して最後に紹介するのは、バージョン1.1で導入されたprovideDelegate()演算子です。これは、委譲先インスタンスを生成できる演算子です。

 リスト3のように、委譲先クラスを用意した場合、byの次にはConnectionFactory()といったそのクラスのインスタンス生成コードを記述しています。単にクラスインスタンスを生成するだけなら、このコードで問題ありませんが、より複雑な処理を行いたい場合に利用するのが、provideDelegate()演算子です。

 例えば、リスト7のコードです。

[リスト7]provideDelegateのコード例
class ConnectionFactoryKai<Owner> {
  operator fun provideDelegate(thisRef: Owner, property: KProperty<*>): ConnectionPool<Owner> {
    connectionの生成処理
    return ConnectionPool(connection)
  }
}

 リスト7では、委譲先クラスとしてConnectionPoolを想定しており、これは、例えばリスト8のコードです。

[リスト8]ConnectionPoolクラスの例
class ConnectionPool<Owner>(
  private val _connection: Connection
) {
  operator fun getValue(thisRef: Owner, property: KProperty<*>): Connection {
    return _connection
  }
}

 リスト8のように、ConnectionPoolクラス内ではConnectionを生成するのではなく、Connectionはあくまで他で生成し、生成されたConnectionを保持しながらその値を委譲元プロパティに委譲するものです。

 この場合は、ConnectionPoolを生成するためのより上位の仕組みが必要で、provideDelegate()演算子をオーバーライドしたリスト7のようなクラスを用意します。

 そして、provideDelegate()内で委譲先であるConnectionPoolインスタンスを生成するコードを記述します。なお、provideDelegate()の引数は、getValue()演算子と同じです。

 こういったConnectionFactoryを用意したら、あとはリスト4と同様にbyの次にConnectionFactoryKai()を記述するだけです。

 さらに、provideDelegate()が記述されたクラス(ここでの例ではConnectionFactoryKai)のインスタンスの生成時に別の処理が必要な場合は、リスト9の(2)のように、ConnectionFactoryKaiインスタンスそのものを生成する関数を用意し、(1)のように、その関数の実行コードをbyの次に記述することも可能です。

[リスト9]ConnectionFactoryKaiを生成する関数を委譲先とした例
class DataProviderKai {
  private val _connection: Connection by createConnectionDelegate()  // (1)
  private fun createConnectionDelegate(): ConnectionFactoryKai<DataProviderKai> {  // (2)
      :
    return ConnectionFactoryKai()
  }
}

 なお、provideDelegateの仕組みに関して、演算子のオーバーライドだけでなく、インターフェースも利用できるようにバージョン1.4で変更されており、その場合はPropertyDelegateProviderインターフェースとします。

委譲プロパティまとめ

 委譲プロパティに関して紹介してきました。ここまでの内容を表2にまとめておきます。

表2:委譲プロパティのパターン
委譲先 内容 委譲コード
他のプロパティ 他で定義されたプロパティと同内容のプロパティを用意する場合に適している by 〇〇::プロパティ名
アクセサを自作したクラス プロパティの生成処理や格納処理コードを自作し、再利用できる by 委譲先クラス()
自作オブジェクト ReadOnlyProperty、または、ReadWritePropertyを実装したオブジェクトを用意する by オブジェクト名
委譲先インスタンスを生成するクラス provideDelegate()メソッドを定義したクラス(PropertyDelegateProviderクラス)を用意することで、その中に委譲先クラス(アクセサを自作したクラス)の生成処理を記述できる by PropertyDelegateProviderクラス()
PropertyDelegateProviderクラスインスタンスを生成する関数 PropertyDelegateProviderクラスインスタンスを生成する際に、さらに別の処理が必要な場合にそれを関数にまとめ、その関数を委譲先とできる by PropertyDelegateProviderインスタンス生成関数

次のページ
インラインクラスの導入

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
【最新Kotlinアップデート解説】バージョン1.1からの変更点総まとめ連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/22092 2025/08/25 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング