Kotlinにおける演算子オーバロードと関数リテラル
Kotlinの関数についてのまとめ、その2。
※英語、または技術的な知識が至らず、内容に誤りが含まれるおそれがありますので、ご了承ください。また、載せているコード例は自作のものであり、参考サイトから引用したものではありません。
※本エントリの8割は参考サイトの翻訳です。残りの2割は私の解釈で加筆や変更を施した構成です。
以前書いたKotlinの関数に関する記事
Kotlinの関数について調べてみた - 算譜王におれはなる!!!!
演算子オーバロード
参考サイト http://confluence.jetbrains.net/display/Kotlin/Operator+overloading
Kotlinでは演算子オーバロードが可能です。その方法はすごくシンプルです。
Groovyのように演算子と、それに対応する関数シグネチャが準備されているというわけです。
定義済みの型(例えばIntやStringBuilderなど)の演算子オーバロードを行いたい場合は、拡張関数として定義します(拡張関数については1月9日の記事で紹介しています)。
fun main(args : Array<String>) { val str = StringBuilder("abcdefg") println(str[0, 3]) // abcd と表示される str[0, 3] = "ABCD" println(str) // ABCDefg と表示される } fun StringBuilder.get(start : Int, end : Int) : String? { return this.substring(start, end + 1) } fun StringBuilder.set(start : Int, end : Int, value : String) { this.replace(start, end + 1, value) }
関数リテラル
参考サイト http://confluence.jetbrains.net/display/Kotlin/Function+literals
関数リテラルは、匿名関数です。
fun main(args : Array<String>) { val array = Array<String>(args.size, {i -> args[i]}) }
Arrayコンストラクタの第2引数に注目してください。そこには、配列の要素の初期化ルールを関数として渡します。上記の例では、その関数を関数リテラルとして直接渡しています。関数リテラルは中括弧( {} )で囲い、引数を冒頭に書き、関数内の処理と細い矢印(->)で区切ります。
上記のように、関数リテラルの取る引数が1つだけの場合に限り、次のように記述することもできます。
val array = Array<String>(args.size, {args[it]})
中括弧内の頭の引数を省略でき、引数の名前は it となります。これはGroovyと同じですね。
関数型
関数を引数として受け取るには、その型を指定する必要があります。Arrayクラスのコードを見てください。
class Array<T>(val size : Int, init : (Int) -> T) { //なんたらかんたら }
第2引数(init : (Int) -> T)に注目してください。これはInt型を引数とし、T型を返す関数を意味し、名前はinitです。
関数リテラルの構文形式
関数リテラルを一切省略せずに書くと、次のようになります。
val less = {(a : Int, b : Int) : Boolean -> a < b}
- 関数リテラルは常に中括弧に囲まれている
- 完全な構文形式における引数の宣言は括弧の内部に書き、型アノテーション(任意)を付ける
- 引数の後に、戻り値の型(任意)を置く
- ボディは -> の後に書く
任意のアノテーションを除くと次のようになります[1]。
val less = {(a, b) -> a < b}
Kotlinでは括弧を除くことも許されています。すると、次のようなコードになります[1]。
val less = {a, b -> a < b}
[1]Kotlin Web Demoでこれらのコードを試すと、何故かコンパイルエラーとなります。コンパイラの不具合か、仕様の変更か…。
クロージャ
関数リテラル(だけでなく、ローカル関数やオブジェクト式)は、そのクロージャ、つまり外側のスコープで宣言された変数にアクセスできます。Javaとは異なり、クロージャ変数の値を変更することもできます。
var x :Int = 2 val square = {x *= x} square() square() square() println(x) //256 が表示される
拡張関数リテラル
Kotlinでは拡張関数をサポートしており、拡張関数リテラルもサポートしています。
val square = { Int.() : Int -> this * this } println(5.square()) //25が表示される