Kotlinスタートブック(赤べこ本) 第6章 の 写経
fun square (i : Int ): Int = i * i
fun main (args : Array <String >) {
println (::square) // fun square(kotlin.Int): kotlin.Int
}
fun square (i : Int ): Int = i * i
fun main (args : Array <String >) {
val fObj = ::square
println (fObj(5 )) // 25
}
03 高階関数 (higher-order function)
fun firstK (str : String ): Int {
tailrec fun go (str : String , index : Int ): Int =
when {
str.isEmpty() -> - 1
str.first() == ' K' -> index
else -> go(str.drop(1 ), index + 1 )
}
return go(str, 0 )
}
fun main (args : Array <String >) {
println (firstK(" " )) // -1
println (firstK(" a" )) // -1
println (firstK(" Ka" )) // 0
println (firstK(" aK" )) // 1
}
fun firstUpperCase (str : String ): Int {
tailrec fun go (str : String , index : Int ): Int =
when {
str.isEmpty() -> - 1
str.first().isUpperCase() -> index
else -> go(str.drop(1 ), index + 1 )
}
return go(str, 0 )
}
fun main (args : Array <String >) {
println (firstUpperCase(" " )) // -1
println (firstUpperCase(" a" )) // -1
println (firstUpperCase(" Aa" )) // 0
println (firstUpperCase(" aA" )) // 1
}
list 6.6 高階関数 first
, 6.7 高階関数 first
の使用例
fun first (str : String , predicate : (Char ) -> Boolean ): Int {
tailrec fun go (str : String , index : Int ): Int =
when {
str.isEmpty() -> - 1
predicate(str.first()) -> index
else -> go(str.drop(1 ), index + 1 )
}
return go(str, 0 )
}
fun firstK (str : String ): Int {
fun isK (c : Char ) = c == ' K'
return first(str, ::isK)
}
fun firstUpperCase (str : String ): Int {
fun isUpperCase (c : Char ) = c.isUpperCase()
return first(str, ::isUpperCase)
}
fun main (args : Array <String >) {
println (firstK(" " )) // -1
println (firstK(" a" )) // -1
println (firstK(" Ka" )) // 0
println (firstK(" aK" )) // 1
println ()
println (firstUpperCase(" " )) // -1
println (firstUpperCase(" a" )) // -1
println (firstUpperCase(" Aa" )) // 0
println (firstUpperCase(" aA" )) // 1
}
04 ラムダ式 (lambda expression)
val square1 = { i: Int ->
i * i
}
val square2: (Int ) -> Int = { i ->
i * i
}
val square2: (Int ) -> Int = {
it * it
}
fun firstWhiteSpace (str : String ): Int {
// fun isWhiteSpace(c: Char) = c.isWhitespace()
// return first(str, ::isWhiteSpace)
// 関数を lambda expression で記述
val isWhiteSpace: (Char ) -> Boolean = { it.isWhitespace() }
return first(str, isWhiteSpace)
}
fun main (args : Array <String >) {
println (firstWhiteSpace(" " )) // -1
println (firstWhiteSpace(" a" )) // -1
println (firstWhiteSpace(" a" )) // 0
println (firstWhiteSpace(" a " )) // 1
}
fun firstWhiteSpace (str : String ): Int =
first(str, { it.isWhitespace() })
list 6.13 ラムダ式 のための syntax sugar
fun firstWhiteSpace (str : String ): Int =
first(str) { it.isWhitespace() }
fun getCounter (): () -> Int {
var count = 0
return {
count++
}
}
fun main (args : Array <String >) {
val c1 = getCounter()
val c2 = getCounter()
println (c1()) // 0
println (c1()) // 1
println (c2()) // 0
println (c1()) // 2
println (c2()) // 1
}
06 インライン関数 (inline function)
fun log (debug : Boolean = true, message : () -> String ) {
if (debug) {
println (message())
}
}
fun main (args : Array <String >) {
log { " output" }
log(false ) { " not output" }
}
Intellij の Show Kotlin Bytecode
-> Decompile
結果
public final class SampleKt {
public static final void log (boolean debug , @ NotNull Function0 message ) {
Intrinsics .checkParameterIsNotNull (message , "message" );
if (debug ) {
Object var2 = message .invoke ();
System .out .println (var2 );
}
}
// $FF: synthetic method
// $FF: bridge method
public static void log$default (boolean var0 , Function0 var1 , int var2 , Object var3 ) {
if ((var2 & 1 ) != 0 ) {
var0 = true ;
}
log (var0 , var1 );
}
public static final void main (@ NotNull String [] args ) {
Intrinsics .checkParameterIsNotNull (args , "args" );
log$default (false , (Function0 )null .INSTANCE , 1 , (Object )null );
log (false , (Function0 )null .INSTANCE );
}
}
list 6.17 の log
関数 に inline
を付ける
inline fun log (debug : Boolean = true, message : () -> String ) {
if (debug) {
println (message())
}
}
Intellij の Show Kotlin Bytecode
-> Decompile
結果
main
の中で log
を呼び出していない
log
の中のロジック(println
-> System.out.println
) が展開されている
public final class SampleKt {
public static final void log (boolean debug , @ NotNull Function0 message ) {
Intrinsics .checkParameterIsNotNull (message , "message" );
if (debug ) {
Object var3 = message .invoke ();
System .out .println (var3 );
}
}
// $FF: synthetic method
// $FF: bridge method
public static void log$default (boolean debug , Function0 message , int var2 , Object var3 ) {
if ((var2 & 1 ) != 0 ) {
debug = true ;
}
Intrinsics .checkParameterIsNotNull (message , "message" );
if (debug ) {
var3 = message .invoke ();
System .out .println (var3 );
}
}
public static final void main (@ NotNull String [] args ) {
Intrinsics .checkParameterIsNotNull (args , "args" );
boolean debug$iv = true ;
String var3 = "output" ;
System .out .println (var3 );
debug$iv = false ;
}
}
Column: noinline と crossinline
inline fun getCounter (crossinline next : (Int ) -> Int ): () -> Int {
var count = 0
return {
count = next(count)
count
}
}
fun main (args : Array <String >) {
val c1 = getCounter { it + 1 }
val c2 = getCounter { it + 1 }
println (c1()) // 1
println (c1()) // 2
println (c2()) // 1
println (c1()) // 3
println (c2()) // 2
}
07 非ローカルリターン と ラベルへのリターン (Non-local returns and Return at Labels)
list 6.20, 6.21 非ローカルリターン の例
inline fun forEach (str : String , f : (Char ) -> Unit ) {
for (c in str) {
f(c)
}
}
fun containsDigit (str : String ): Boolean {
forEach(str) {
if (it.isDigit()) return true
}
println (" $str に数字が含まれている場合、ここは実行されない" )
return false
}
fun main (args : Array <String >) {
println (containsDigit(" " )) // false
println (containsDigit(" " )) // false
println (containsDigit(" a" )) // false
println (containsDigit(" 1a" )) // true
}
fun containsDigit (str : String ): Boolean {
var result = false
forEach(str) here@{
if (it.isDigit()) {
result = true
return @here
}
}
println (" $str に数字が含まれていても、ここは実行される" )
return result
}
fun containsDigit (str : String ): Boolean {
var result = false
forEach(str) {
if (it.isDigit()) {
result = true
return @forEach
}
}
println (" $str に数字が含まれていても、ここは実行される" )
return result
}
追記: lambda -> anonymous function に変更してみる
fun containsDigit (str : String ): Boolean {
var result = false
forEach(str, fun (c : Char ) {
if (c.isDigit()) {
result = true
return
}
})
println (" $str に数字が含まれていても、ここは実行される" )
return result
}
08 無名関数 (anonymous function)
// lambda expression
val square1: (Int ) -> Int = { i ->
i * i
}
// anonymous function
val square2: (Int ) -> Int = fun (i): Int {
return i * i // return 使用
}
// anonymous function ({} 省略バージョン)
val square3: (Int ) -> Int = fun (i) = i * i
fun main (args : Array <String >) {
println (square1(2 )) // 4
println (square2(3 )) // 9
println (square3(4 )) // 16
}