クラスの継承に関する話題が出てきたので、キャストについても考えておきましょう。
KotlinはJavaと同様に静的な型付け言語なので、データ型はコンパイル時点で確定されます。そのため、Javaと同様に型のキャストが必要になる場面があります。Kotlinではリスト10のように「as」演算子を使ってキャストします。C/C++/C#のように「(型名)変数」の形式ではキャストできないので、ご注意ください。
val cat = Cat() //「Cat」型(「Animal」型を継承)のインスタンス val animal = cat as Animal //Animal型にキャスト //val animal2 = (Animal)cat //この形式はエラー
キャストに失敗した場合、as演算子は例外を送出します。as演算子の代わりに「as?」演算子を使うと、キャストに失敗した場合にnullが返ります。
キャストが必要になるケースにおいては、多くの場合、事前の型チェックがセットになります。Javaであればリスト11のような「型をチェックしてマッチしたらキャストして使う」というコードを書いたことがあるかもしれません。
void action(Object something){ //引数がColor型だったら if(something instanceof Color){ //いったんキャストする Color c = (Color)something; …… }else if(something instanceof Point){ Point p = (Point)something; …… } }
Kotlinであれば、同じコードをリスト12のように書けます。Javaの「instanceof」の代わりにKotlinでは「is」を使ってオブジェクトの型をチェックします。
//引数としてAny fun action(something: Any){ //when文で型ごとに分岐 when(something){ //X,YはPoint型のプロパティ、R,G,BはColor型のプロパティとする //somethingをキャストせずに使っている↓ is Point -> println("Point: {something.X}, {something.Y}") is Color -> println("Color: [{something.R},{something.G},{something.B}]") } }
注目したいのは「when」の中でisを使って分岐した中のコードです。「something.X」「something.R」のように、キャストしていないのに、「something」引数を「Point」型や「Color」型のオブジェクトとして参照しています。ここでは「事前にisで型をチェックしているのだから、自動的にその型として扱う」という仕組みが働いています。これを「スマートキャスト」と呼び、whenだけではなくifでも使用できます(リスト13)。
//ifの条件式で型チェック済 if(something is Point){ println("Point: {something.X}, {something.Y}") //キャストなしで使える }else if(something is Color){ println("Color: [{something.R},{something.G},{something.B}]") }
スマートキャストを使うことで、型チェックによる分岐コードを書く際の自明なキャストが不要になりますね。これもまた「Kotlinにしてよかった」と思える瞬間です*3。
*3)ちなみにC# 7では、「パターンマッチング」と呼ばれる機能によってキャストを省略できる仕組みが導入されました。Kotlinとは違ったアプローチですが、シンプルな記述法となっています。興味のある方は以下の記事を参照してください。
今回はクラス継承に関するもろもろの機能について解説しました。やはりベースとなっているJavaに似ている部分が多いですが、インタフェースにプロパティを持てる部分など、ちょっとした違いにより書きやすさが向上している面もあります。
また、スマートキャストは静的な型付け言語を使う際に煩わしく感じる自明なキャストの手間を省いてくれます。こちらも小粒ですが、うれしい機能ですね。
最終回となる次回は、拡張関数、範囲(Range)、分解宣言と多重戻り値など、残っている目玉機能をできる限り総ざらいする予定です。どうぞお楽しみに。
Copyright © ITmedia, Inc. All Rights Reserved.