Skip to content

Instantly share code, notes, and snippets.

@ohtsuchi
Last active September 30, 2017 16:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ohtsuchi/262c2d55f75f8d6c35d86c601acdf5eb to your computer and use it in GitHub Desktop.
Save ohtsuchi/262c2d55f75f8d6c35d86c601acdf5eb to your computer and use it in GitHub Desktop.
Kotlinスタートブック(赤べこ本) 第6章 の 写経

Kotlinスタートブック(赤べこ本) 第6章 の 写経


01 関数オブジェクト

list 6.1

fun square(i: Int): Int = i * i

fun main(args: Array<String>) {
    println(::square) // fun square(kotlin.Int): kotlin.Int
}

list 6.2

fun square(i: Int): Int = i * i

fun main(args: Array<String>) {
    val fObj = ::square
    println(fObj(5)) // 25
}

02 関数型


03 高階関数 (higher-order function)

list 6.3

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
}

list 6.4

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.5

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)

list 6.8

list 6.9 ラムダ式 における型推論

val square1 = { i: Int ->
    i * i
}
val square2: (Int) -> Int = { i ->
    i * i
}

list 6.10 暗黙の変数 it

val square2: (Int) -> Int = {
    it * it
}

list 6.11 ラムダ式 と 高階関数

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
}

list 6.12 ラムダ式 をそのまま引数に

fun firstWhiteSpace(str: String): Int =
        first(str, { it.isWhitespace() })

list 6.13 ラムダ式 のための syntax sugar

fun firstWhiteSpace(str: String): Int =
        first(str) { it.isWhitespace() }

05 クロージャ (closure)

list 6.14

list 6.15, 6.16

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)

list 6.17

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.18 インライン関数

  • 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;
   }
}

list 6.19


Column: noinline と crossinline

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
}

list 6.22 ラベルへのリターン

fun containsDigit(str: String): Boolean {
    var result = false
    forEach(str) here@{
        if (it.isDigit()) {
            result = true
            return@here
        }
    }
    println("$str に数字が含まれていても、ここは実行される")
    return result
}

list 6.23 関数名を指定したリターン

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)

list 6.24

// 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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment