新言語KotlinでAndroidプログラミング #DroidKaigi

  • 52
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

なんの記事?

去る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_
    }
}

この新しいバージョンのUsernameにアクセスすると「呼ばれたぞ」と出力されます。

関数オブジェクト

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 }

abcどれも同じことをしていますが、複数の書き方があるということです。
関数オブジェクトの利点は、関数を持ち回って好きな場所で関数を呼び出せることです。

トップレベルの関数

Kotlinはクラスに属さない関数や変数を定義できます。これらはJava的にどう表現されるのか、についてですが、一言で言うと「パッケージ名Package」という名前のクラスが作られ、そのクラスのstaticメンバとなります。

package hoge.fuga

val piyo = "Piyopiyo"

このpiyoをJavaコードから参照するにはhoge.fuga.FugaPackage.piyoという名前を使います。

追記予定...?

スライドの中で質問とかあればできる限り答えたいと思います。