Kotlin Advent Calendar 2012 (全部俺)

JavaプログラマのためのKotlin入門

5日目:変数と型

f:id:ngsw_taro:20121204062934j:plain

アドベントカレンダー5日目の今日はKotlinにおける変数と型について紹介します。型については少し触れる程度にします。

変数

Kotlinで変数を宣言するにはキーワードを伴う必要があります。

var x : Int
これはJavaでは次に相当します。 
// Java
int x;

キーワード var で変数を宣言しており、続けて変数名、コロンを指定します。変数の宣言と同時に初期化することもできます。

var x : Int =

型推論

昨日も少し触れましたが、Kotlinには型推論という機能があります*1。型推論とは文字通り型の推論です。つまり、プログラマが型を明記しなくてもコンパイラが文脈から推論して適切な型として扱ってくれるということです。次の変数宣言・初期化は型推論を利用して簡潔に記述しています。

var x = 

これは素晴らしいことです。1つ前のバージョンから冗長性を排除しました。整数リテラルはInt型なので、それを代入しようとしている変数の型がInt型なのは明記するまでもないのです。型推論は、静的言語の動的言語に対する重要な短所のひとつである型記述の煩わしさを解消する機能です。

変更不可の変数

もう1つ変数宣言のキーワードがあります。val です。次のコードは val を使って不変の変数を宣言・初期化しています。

val x = 0

これは次のJavaコードに相当します。

// Java
final int x = 10;

変数を変更不可にするのは、関数型プログラミング的なアプローチです*2。値が不変であることはいいことです。コードの読み手が、その変数が不変であることによって、他の箇所で値が書き変わることを心配する必要がなく安心してコードを読めるからです。また変数やオブジェクトの内部状態が不変であることによって、関数の返す値を予測しやすくなります。これを参照透過性と言ったりします。オブジェクトの内部状態が変更可能であると、それに属する関数の返す値が内部状態の変更に伴って変わるおそれがあり、予測が困難です。

基本型

Kotlinではすべてオブジェクトです。そのため基本型という呼ぶ方は正確ではないような気がしますが、Javaの基本型(プリミティブ型)に対応する型として聞いていただければと思います。

数値型

Kotlinの基本の数値型はJavaの数値型の頭文字を大文字にしたものと同じです。要するに、ビット幅の大きいものから整数型はLong、Int、Short、Byte、浮動小数型はDouble、Floatです。

注意していただきたいのは、Kotlinには暗黙の型変換がありません。これはJavaよりも慎重な設計です。暗黙な型変換は時にプログラマに複雑なルールを強いることになるからでしょう。

val a = 5
val b : Long = a // ERROR
val c : Long = a.toLong() // OK
val d : Long = a as Long // OK

いわゆる四則演算はいつも通り、+ - * / といった記号が使用できますが、論理演算/ビット演算の記号は用意されていません。これらは関数呼び出しによる演算を行う必要があります。

関数名意味
shl 左シフト
shr 符号付き右シフト
ushr 符号なし右シフト
and 論理積
or 論理和
xor 排他的論理和
inv ビット反転

使用例を示します。

val a = 0b0110 // 0bを先頭に置くと2進数リテラルとなる
val b = 0b1100
println(a and b == 0b0100) // true

上記の例では、関数 and を演算子のように使用しています。つまりレシーバと関数の間にドットがなかったり、引数を括弧で囲まなかったりです。このような関数呼び出しを中置呼び出しと言いますが、詳細は後日お話しします。

文字

文字はChar型によって表現されます。文字リテラルJavaと同様にシングルクォートで囲みます。文字は数値として直接扱うことはできません。明示的な型変換により、Int型の数値に変換することができます。

真偽値

真偽値はBoolean型によって表現されます。取り得る値は true と false です。組み込み演算子として || と && が提供されています(Javaと同様の意味)。

文字列

文字列はクラス String によって表現されます。文字列は不変オブジェクトで、その構成要素は文字です。 Kotlinには2種類の文字列リテラルがあります。1つはJavaと同様の形であるエスケープ文字列("Hello\n"など)です。もう1つは原型文字列です。これは名前の通り、エスケープ文字や改行をそのままの形で解釈します。原型文字列を定義するには、トリプルクォート(""")で文字列を括ります。

文字列に、テンプレート式を含むことができます。テンプレート式とは、式が評価された結果を文字列内に組み込む仕組みです。$変数名もしくは${ 式 }と表現します。例を次に示します。 

println("$str") // hello
println("${str.length}") // 5

Unit型

特に興味深い値を持たないという意味では、Javaの void と似ていますが、型 Unitは void とは異なり値を1つだけ取り得ます。その値は Unit.VALUE です*3。一見、何も返さないような関数でも返り値の型はUnitで Unit.VALUE をきちんと返しています。

まとめと次回予告

今日は変数の宣言・初期化の方法と型推論、そして基本型とそれにまつわる関数や演算子を学びました。Kotlinでは基本的に変数宣言の箇所では型を省略します。また、特別な理由がない限りは不変な変数としてキーワード val を使用して宣言したほうがいいでしょう。Kotlinには暗黙の型変換がありません。明示的に型変換します。一見煩わしいですが、複雑な型変換ルールからプログラマは解放されます。文字列リテラルとしてテンプレート式という便利な機能を見ました。

明日は条件分岐について紹介します。お楽しみに!

日記

昨夜は会社の同期たちと飲みました。久しぶりの再会に盛り上がりました。

*1:Javaの現行バージョンにも型推論機能はありますが、Kotlinのそれの方が強力です。

*2:通常のJavaプログラミングでも大切なことには変わりないです。

*3:古いバージョンのKotlinでは() でした。これは要素が0個のタプルを表しています。現バージョンではタプルが廃止されているのでUnitのクラス定数となったのでしょう。