背景
Kotlinでコード書いてる時Pythonで言うところのデコレータを使いたかったが、検索しても見つけられませんでした。
クラス委譲というものが出てきましたが、コレジャナイ感。
C系とjava系だからそんなものかと思いつつ、とりあえず書いてみたという話です。
補足 デコレータって?
関数やクラスを文字通り「装飾」する機能のこと。これにより既存の関数やクラスの中身を直接触らず、その外側から機能を追加したり書き換えたりすることができる。
詳しくはこの記事を見てください。
Pythonのデコレータの例
さっき貼った記事のコードと同じです。
コード
#デコレータを定義
def greet(func):
def inner(*args,**kwargs):
print("こんにちは。")
result = func(*args,**kwargs)
print("よろしくお願いします。")
return result
return inner
#使い方
@greet
def myName(name):
print(f"私は{name}です。")
return "挨拶 終"
print(myName("ねこでべろん"))
デコレータによって装飾された引数をとる新たな関数が返され、それを引数付きで実行することで結果を得ています。
結果
こんにちは。
私はねこでべろんです。
よろしくお願いします。
挨拶 終
kotlinで再現
とりあえず素直に書き変えようとすると、、、
fun <R> greet(func:(funcの引数の型)->R):(funcの引数の型)->R{
}
無理です。
funcの引数の型
は引数の個数も種類もこの時点では決まってないので書けません。
種類が決まっていないのは対応できますが、数が決まっていないのがきついです。可変長引数も使って試行錯誤してみましたが私には無理でした。
諦めて少しロジックを変えます。
コード
//デコレータを定義
fun <T> greet(func:()->T):()->T{
fun wrapper():T{
println("こんにちは。")
val result = func()
println("よろしくお願いします。")
return result
}
return ::wrapper
}
//デコレータに渡すための処理
fun myName(name:String):String{
//実際の処理
fun _myName():String{
println("私は${name}です。")
return "挨拶 終"
}
return greet(::_myName)()
}
fun main() {
println(myName("ねこでべろん"))
}
引数が邪魔なので、デコレータに与える関数を引数に特化させます。
デコレータからは引数に特化しかつ装飾された関数が返ってきます。
これを実行することで結果が得られるというわけです。
実行部分だけ見れば似ていますが、内部的には全然違います。
結果
こんにちは。
私はねこでべろんです。
よろしくお願いします。
挨拶 終
一般化
とりあえず載せます。
//デコレータ
fun <T> decorater(func:()->T):()->T{
fun wrapper():T{
ToDo()
val result = func()
ToDo()
return result
}
return ::wrapper
}
//関数
//Typeは同じ型
fun function(arguments):Type{
fun _function():Type{
ToDo(arguments)
return result
}
return decorater(::_function)()
}
最後に
今回はPythonのデコレータを再現してみました。
完全再現という訳には行かなかったのが少し悔しいです。
Pythonが動的型付け、Kotlinが静的型付けということでやはり型で苦労しましたね。
完成したものも各方面から怒られそうですが、その方々には加筆してもらうつもりです。
記事の内容に誤りがあればコメントや加筆等よろしくお願いします。