Kotlinというプログラミング言語を用いたAndroid開発が注目を集めています。
Kotlinの基本的な構文を知らないと始まらないのでJavaとの違いを押さえつつ確認していきましょう!
今回は関数についてです。
## 関数
最も簡単な例から見ていきましょう。
1 2 3 | int addOne( int num) { return num + 1 ; } |
1 2 3 | fun addOne(num: Int): Int { return num + 1 } |
funキーワードを用いること、引数と戻り値の型の書き方が異なる以外そんなに変わらないですね。
ただクラス内でしか宣言できなかったJavaと違い、Kotlinの関数はモジュールのトップレベルに宣言することが可能です。
戻り値なし
Kotlinでは関数は必ず値を返します。ただ有意な値を返す必要がない場合もあるのでそのような場合はUnit型の値を返します。Javaのvoidのようなものですね。
1 2 3 | void printWithPrefix(String text) { System.out.print( "Prefix" + text); } |
1 2 3 | fun printWithPrefix(text: String): Unit { print( "Prefix" + text) } |
なおUnit型の戻り値型の指定は省略しても構いません。
ローカル関数
Kotlinは関数ブロックの中で関数を宣言することが可能です。
1 2 3 4 5 6 7 8 9 10 | fun tryCount() { fun countUp(count: Int): Int { return count + 1 } var count = 0 while (count < 10 ) { count = countUp(count) } } |
当然ですが、関数内関数のスコープはラップしている関数ブロックですので、外から呼ぶことはできません。
クロージャ
Kotlinはクロージャをサポートしているのでスコープ外のローカル変数を操作することができます。
(Javaではfinalを付ける必要があり、かつreadonlyでしたね)
1 2 3 4 5 6 7 8 9 10 11 | fun tryCount() { var count = 0 fun countUp() { count + 1 } while (count < 10 ) { countUp() } } |
デフォルト引数
引数にデフォルト値を指定することができます。
デフォルト値が指定してある引数は、関数呼び出し時に省略することができます。
1 2 3 4 5 6 | fun addPrefix(text: String, prefix: String = "pre" ): String { return "$text$prefix" } addPrefix( "foo" ) addPrefix( "foo" , "bar" ) |
名前付き引数
次の関数はStringクラスの拡張関数で文字列中のcharの置換を行う拡張関数の定義です。
1 2 3 | public fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boolean = false ): String { ... } |
この関数を呼び出すときこのように記述できます。
1 | "character" .replace(oldChar = 'c' , newChar = 'a' , ignoreCase = false ) |
引数の数が多いときにこのように書くことで可読性を上げることができます。
高階関数
Kotlinにおいて関数リテラルによる関数は第一級オブジェクトです。第一級オブジェクトとは変数や引数、戻り値に入れることができる対象を指します。
この性質により簡潔かつ柔軟なプログラムが可能です。
無名関数
関数リテラルを表す記述の一つが無名関数です。
1 2 3 4 5 6 7 8 9 10 11 | fun calc(num: Int, func: (Int) -> Int): Int { return func(num) } calc( 5 , fun(num: Int): Int { return num * 2 }) calc( 5 , fun(num: Int): Int { return num + 1 }) |
整数にこのようにfunキーワードを用いつつ、関数名のないものが無名関数です。
ラムダ式
関数リテラルのもう一つの記述方法がラムダ式です。
上の例をラムダ式を用いて書くと次のようになります。
1 2 | calc( 5 , { num -> num * 2 }) calc( 5 ){ num -> num + 1 } |
ラムダ式の場合は明示的な戻り値の型宣言はありません。型推論で行われます。
関数が末尾引数の場合はブロックを引数の括弧の外に出すことが可能です。
SAM変換
Javaにおいてメソッドが一つのインターフェースをSAM(SingleAbstractMethod)インターフェースと呼びます。
Kotlinのラムダ式は、SAMインターフェースを実装する無名クラスに変換されます。
これはAndroid開発で頻繁に出てくるコールバックインターフェースの実装が簡潔に記述できることを意味します。
1 2 3 4 5 6 | button.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { Log.v( "tag" , "clicked" ); } }); |
1 2 3 4 5 | button.setOnClickListener { v: View -> Log.d( "tag" , "clicked" ) } //省略形 button.setOnClickListener { v -> Log.d( "tag" , "clicked" ) } button.setOnClickListener { Log.d( "tag" , "clicked" ) } |
ノイズが減って非常に簡潔になりましたね。Kotlinの良さの一端です。
Kotlinにおける関数の基本を紹介しました。基本だけでもJavaに比べて柔軟な実装ができることが伺えると思います。