連載
» 2018年05月14日 05時00分 公開

Android Studioで始めるKotlin入門(6):Kotlinの拡張関数、範囲、分解宣言と多重戻り値、演算子オーバーロード (3/3)

[土井毅(著)/山田祥寛(監修),WINGSプロジェクト]
前のページへ 1|2|3       

演算子オーバーロード

 C++やC#などのオブジェクト指向言語で一般的ながら、Javaでサポートされていない機能の1つが「演算子オーバーロード」です。端的に言えば「自分で定義したデータ型についても、組み込みデータ型と同様に演算子を使えるようにする」機能です。

 例として複素数を表現するクラスを自分で定義するケースを考えてみましょう。リスト10は演算子オーバーロードが使える言語、使えない言語でのサンプルです。

//C#的なサンプル。演算子オーバーロードが使える場合
var c1 = new Complex(1, 2);
var c2 = new Complex(-1, 2);
var c3 = c1 + c2; //普通に+演算子が使える
 
//Java的なサンプル。演算子オーバーロードが使えない場合
Complex c1 = new Complex(1, 2);
Complex c2 = new Complex(-1, 2);
Complex c3 = c1.add(c2); //演算子の代わりにaddメソッドで加算する
リスト10 演算子オーバーロードが使える言語、使えない言語での書き方の違い

 演算子オーバーロードがサポートされている言語であれば、+、-などの演算子をどのように処理するかも自分で実装できるので、数値型などと同じような使い方ができます。

 一方、演算子オーバーロードをサポートしない言語の場合、add、subなどの演算子に相当するメソッドを定義し、演算子を使う代わりにそれらのメソッドを使って書かなければなりません。

 演算子オーバーロードが使えると、より直感的に記述できることがよく分かりますね。

 Kotlinではoperatorキーワードを使って、メソッドのように演算子オーバーロードを定義します。リスト11では、自作の複素数クラス(整数のみ対応)で+演算子、-演算子(2項)、-演算子(単項)を定義しています。

//自作の複素数クラス(整数のみ対応)
data class Complex(val real: Int, val image: Int){
  //operatorキーワードを使って+演算子をオーバーロード
  operator fun plus(value: Complex): Complex{
    return Complex(real + value.real, image + value.image)
  }
  //-演算子(2項)
  operator fun minus(value: Complex): Complex{
    return Complex(real - value.real, image - value.image)
  }
  //-演算子(単項)
  operator fun unaryMinus(): Complex{
    return Complex(-real, -image)
  }
  //複素数的な表記を返すように文字列化
  override fun toString(): String{
    if(image > 0)
      return "$real+${image}i"
    else
      return "$real${image}i"
  }
}
……
//複素数クラスを使ってみる
var c1 = Complex( 2, 2)  //  2+2i
var c2 = Complex(-1, 5)  // -1+5i
var c3 = c1 + c2 //普通に+演算子が使える
 
println(c3)      //加算結果     「1+7i」
println(c1 - c2) //減算結果     「3-3i」
println(-c1)     //単項の-演算子「-2-2i」
リスト11 複素数クラスでの演算子オーバーロードの例

 ここでは、+演算子、-演算子(2項)、-演算子(単項)に対応するメソッドとして、operatorキーワードを使ってplus、minus、unaryMinusメソッドを記述しています。

演算子をオーバーロードする際のメソッド名の一覧

 メソッド名は演算子ごとに表1のように定められています。

表1 演算子をオーバーロードする際のメソッド名
演算子 メソッド名
+ plus
- minus
* times
/ div
% rem
+= plusAssign
-= minusAssign
*= timesAssign
/= divAssign
%= remAssign
++ inc
-- dec
+(単項) unaryPlus
-(単項) unaryMinus
.. rangeTo
! not
in contains
[] get / set
() invoke
== equals
>、< compareTo

 四則演算子などはごく自然な対応だと思いますが、配列アクセスのように使える[]演算子、果ては関数呼び出しに相当する()までオーバーロードが可能というのは驚きですね*3

*3)概ねC#よりも演算子オーバーロード可能な演算子は多めで、C++に近いようです。

 実は前述の「範囲」で使用する..演算子やin演算子もオーバーロードで実現されています。本連載でここまで解説してきたKotlinの言語機能の幾つかについても、演算子オーバーロードが活用されています。

注意点

 このように、演算子オーバーロードは強力で便利な機能ですが、演算子の実装の仕方によっては、データ型の利用者が想定しない挙動になることもあります。直感に反する実装や、予期しない副作用を起こすような実装は避けましょう。

その他注目のKotlinの言語機能

 全6回にわたってKotlin言語について解説してきましたが、いかがだったでしょうか。扱い切れなかった機能もまだまだあります。注目株をご紹介しましょう。

可変長引数と名前付き引数

 Java 5から可変長引数がサポートされていますが、Kotlinでも関数で可変長引数を使うことができます。また、名前付き引数は引数のデフォルト値と組み合わせるケースで引数の対応関係がとても分かりやすくなります。

中置記法(infix notations)

 一定条件を満たすメソッド(拡張関数含む)を、「obj.methodA(param)」と書く代わりに「obj methodA param」のように書くことができます。

 例えば「範囲」のサンプルとして示した「9 downTo 1 step 2」のdownToやstepはKotlin言語自体に備わったキーワードや演算子ではなく、拡張関数の呼び出しを中置記法で書いたものです。中置記法を使わずに書くと「9.downTo(1).step(2)」のようになります。言語をむやみに拡張せずに自由度の高い書き方ができる、見事な機能ですね。

委譲プロパティ(Delegated Properties)

 プロパティのアクセサ処理を他のオブジェクトに委譲する機能で、これによってアクセス時に初めて計算される遅延プロパティなどが実現できます。

 その他、インライン関数(関数の中身が呼び出し場所に展開される)やスコープ関数(オブジェクトに複数の処理をまとめて適用するなど多彩な機能)、型安全ビルダー(HTMLなどのマークアップ言語をサクサク書ける)など、Javaにはない興味深い機能もあるので、関心があればぜひレファレンスなどを参照してください。

終わりに:Kotlinに限らず、新しいプログラミング言語との向き合い方について

 さて本連載では、これまで見てきた通り、KotlinはJavaより「簡潔」「直感的」「書きやすい」「読みやすい」という言葉を何度も繰り返してきましたが、これは何もJavaをむやみにおとしめてKotlinを褒めちぎろうとしているわけではありません。

 Javaも初期バージョンからすれば多彩な言語機能をのみ込み続け、より高機能な言語へと進化し続けています*4。とはいえ、言語設計時にあらかじめ想定されていなかった機能を、互換性を保ちながら後付けすることは、ある場合には非常に困難で、非直感的な実装にならざるを得ない場合もあります。

*4)ローカル変数の型推論がJava SE 10でサポートされたのはその良い例ですね。

 一方で、KotlinやSwiftなど、新たに生まれた言語が、新しい機能を想定して(あるいはさらなる拡張を見据えて)言語仕様を決めることで、より簡潔で可読性の高い記述にできるのは当然のことといえるでしょう。

 本連載でもJavaを中心にC#など他言語との比較を取り上げましたし、「Kotlinを使えばやゆされなくなる」などというフレーズも含めてみましたが、言語間の差異を何か宗教論争のように取り上げることは本意ではありません。前述の通り、特定の分野での言語の優劣は登場時期に起因する場合もあります。そうしたことを踏まえて「言語が優れている=その言語を使うプログラマーが優れている」などという勘違いに陥らないようにしたいものです。

 ともあれ、新しい言語の多彩な機能に触れるのはプログラマーにとって刺激的で、新鮮な体験だと思います。本連載がKotlin開発に取り組む皆さまの一助となることを祈りつつ、連載の結びといたします。

今回のサンプルコード

 今回のサンプルコードはこちらからダウンロードできます

前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。