なんの記事?
去る4月25日にDroidKaigiというAndroid技術カンファレンスに参加して来ました。そこで本記事と同名のタイトルで発表させていただきました。25分間という短い時間の中で、丁寧に説明できなかった箇所をフォローしたいと思います。
スライドはこちら!
発表の趣旨
Kotlinというプログラミング言語の紹介です。
Kotlinを使ったAndroidプログラミングの布教が目的です。
KotlinはJVM言語
Kotlinで記述されたコードは、KotlinコンパイラによりJVM(Java仮想マシン)上で動作するバイトコードに変換されます。そのためKotlinコードからJavaコードを呼び出すことがわりと簡単にできます(もちろんその逆も)。具体的にはJava標準ライブラリのInteger#parseInt
をKotlinコードから呼び出したり、AndroidのActivity
をKotlinコードで定義したクラスで継承したり、ということが可能です。
また、KotlinはAndroid上での動作もサポートしています。これは単にJVM言語と言ったときには含まない強みです。
Kotlinは静的型付け
KotlinはJavaと同様に静的に、つまり実行前に型が解決されます。例えば文字列を整数値として扱うようなソースコードは、実行可能コードには変換されません。コンパイルタイムのエラーとなるということです。何が嬉しいのかと言うと、「文字列を整数値として扱う」のようなオブジェクトの取り扱いミスを未然に防いでくれることです。
Kotlinの配列は不変
読み飛ばしてください(そこまで大きなトピックではないので)。
Javaの配列は共変(covariant)です。共変なのですが、危険な操作が可能です。
// Java
// コンパイルは通るけどクラッシュする
Integer[] ints = {1};
Number[] nums = ints;
nums[0] = 0.5; // ここで例外
一方Kotlinの配列は不変(invariant)です。
val ints: Array<Int> = array(1)
val nums: Array<Number> = ints // ここでコンパイルエラー
配列を共変として扱うことももちろんできます。そして安全です。
val ints: Array<Int> = array(1)
val nums: Array<out Number> = ints // OK
nums[0] = 1 // ここでコンパイルエラー
Kotlinのプロパティ
Kotlinのクラスはプロパティを持てます。それはJavaで言うフィールドとアクセサ(getter/setter)の合体したやつ、というとわかりやすいかも知れません。
// nameプロパティを持ったUserクラス
// 例示のためまわりくどい記述になっています
class User(private val name_: String) {
val name = name_
}
今定義したUser
クラスをインスタンス化してname
プロパティからユーザ名を取得してみます。
val taro = User("Taro")
println(taro.name) // => Taro
name
というpublicなフィールドにアクセスしているように見えますが実はgetterを経由しています。
それを確かめるためにカスタムgetterを定義します。
class User(private val name_: String) {
val name: String
get() {
println("呼ばれたぞ")
return name_
}
}
この新しいバージョンのUser
のname
にアクセスすると「呼ばれたぞ」と出力されます。
関数オブジェクト
Kotlinの関数(あるいはメソッド)は、通常のオブジェクトのように変数に代入したり、関数の引数として渡したりすることができます。
簡単な関数を定義して、使ってみます。
fun succ(n: Int) = n + 1
succ(1) // => 2
次に、この関数succ
を変数に代入して、その変数を介して関数の機能を実行します。
val funcObject = ::succ
funcObject.invoke(3) // => 4
funcObject
がまさに関数オブジェクトです。関数を実行するにはinvoke
メソッドを呼び出します。invoke
メソッドを呼び出す代わりに本物の関数のような呼び出しも可能です。
funcObject(5) // => 6
上記の例では、関数を定義→変数に代入という流れでしたが直接関数オブジェクトを記述することもできます(関数リテラルと呼んだりします)。
val a = fun(n: Int) { return n + 1 }
val b = fun(n: Int) = n + 1
val c = { n: Int -> n + 1 }
a
、b
、c
どれも同じことをしていますが、複数の書き方があるということです。
関数オブジェクトの利点は、関数を持ち回って好きな場所で関数を呼び出せることです。
トップレベルの関数
Kotlinはクラスに属さない関数や変数を定義できます。これらはJava的にどう表現されるのか、についてですが、一言で言うと「パッケージ名Package」という名前のクラスが作られ、そのクラスのstaticメンバとなります。
package hoge.fuga
val piyo = "Piyopiyo"
このpiyo
をJavaコードから参照するにはhoge.fuga.FugaPackage.piyo
という名前を使います。
追記予定...?
スライドの中で質問とかあればできる限り答えたいと思います。