Created
September 7, 2017 03:48
-
-
Save tikidunpon/fa6f7be51e3e023d4872abc9b9479abc to your computer and use it in GitHub Desktop.
Kotlinスタートブック読書勉強会 #4 第6章 第一級オブジェクトとしての関数 (参考資料)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by koichitanaka on 2017/06/11. | |
*/ | |
fun <T> println(message: T) { | |
print(Thread.currentThread().stackTrace[2].lineNumber.toString() + "行目 ") | |
print(message) | |
print("\n") | |
} | |
fun square(i: Int): Int = i * 1 | |
fun main(args: Array<String>) { | |
// p82 関数オブジェクトを::関数名で取得できる | |
println(::square) | |
// p82 関数オブジェクトを通して関数を呼べる | |
val functionObject = ::square | |
println(functionObject(5)) | |
val functionObject2: (Int) -> Int = ::square | |
println(functionObject2(5)) | |
// p83 型指定(Intを引数にとり、Intを返す関数型) | |
val functionObject3: (Int) -> Int = ::square | |
// ↓のfunctionObject3を選んでCtrl+Shift+Pで型が見られます。 | |
println(functionObject3) | |
// p84 高階関数 | |
// 最初にKが出現する位置を返す関数 | |
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) | |
} | |
println(firstK("You are a perfect Kotliner.")) | |
// p85 高階関数 | |
// 最初に大文字が出現する位置を返す関数 | |
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) | |
} | |
// p85の擬似コードの説明。str.first()に対する何らかの条件部分は、 | |
// 「文字を引数にとって、Booleanを返す関数」とできそう。 | |
// p86 高階関数 | |
// 高階関数 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) | |
} | |
// p86 高階関数 | |
// 高階関数firstの使用例 | |
fun firstK2(str: String): Int { | |
fun isK(c: Char): Boolean = c == 'K' | |
return first(str, ::isK) | |
} | |
// 高階関数firstの使用例 | |
fun firstUpperCase2(str: String): Int { | |
fun isUpperCase(c: Char): Boolean = c.isUpperCase() | |
return first(str, ::isUpperCase) | |
} | |
// p87 ラムダ式 | |
// ラムダ式の例 | |
val square: (Int) -> Int = { i: Int -> | |
i * i | |
} | |
// ラムダ式における型推論1 | |
val square1 = { i: Int -> | |
i * i | |
} | |
// ラムダ式における型推論2 | |
val square2: (Int) -> Int = { i -> | |
i * i | |
} | |
// p88 ラムダ式 | |
// 暗黙の変数 it | |
// val square2: (Int) -> Int = { | |
// it * it | |
// } | |
// ラムダ式と高階関数 | |
fun firstWhitespace(str: String): Int { | |
val isWhitespace: (Char) -> Boolean = { | |
it.isWhitespace() | |
} | |
return first(str, isWhitespace) | |
} | |
// ラムダ式をそのまま引数に | |
fun firstWhitespace2(str: String): Int = | |
first(str, { it.isWhitespace() }) | |
// ラムダ式の為の構文糖衣 | |
fun firstWhitespace3(str: String): Int = | |
first(str) { it.isWhitespace() } | |
// p90 クロージャ | |
// 別の関数で定義された変数は見れない | |
fun foo(): Int { | |
val a = 1 | |
val b = 2 | |
return a + b | |
} | |
// fun bar(): Int { | |
// val c = 3 | |
// return a + c //aにアクセスできずコンパイルエラー | |
// } | |
// 関数オブジェクトを返す関数getCounter | |
fun getCounter(): () -> Int { | |
var count = 0 | |
return { | |
count++ | |
} | |
} | |
val counter1 = getCounter() | |
val counter2 = getCounter() | |
println(counter1()) // 0が出力される | |
println(counter1()) // 1が出力される | |
println(counter2()) // 0が出力される | |
println(counter1()) // 2が出力される | |
println(counter2()) // 1が出力される | |
// 実行時ではなく、コードを記述した時のスコープで変数が扱える関数オブジェクトをクロージャと呼ぶ | |
// クロージャwiki https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B8%E3%83%A3 | |
// p92 インライン関数 log関数にinlineをつけて確認 | |
log { "このメッセージは出力される" } | |
log(false) { "このメッセージは出力されない" } | |
// p94 | |
println(square(3)) | |
println(getCounterInlined( square )) | |
// p95 非ローカルリターンラベルへのリターン | |
// 非ローカルリターンの例 | |
containsDigit1("abc45efg") | |
// ラベルへのリターンの例 | |
containsDigit2("abc45efg") | |
// 関数名を指定したリターン | |
containsDigit3("abc45efg") | |
// p97 無名関数 | |
// ラムダ式 | |
val square3: (Int) -> Int = { i: Int -> | |
i * i | |
} | |
// 無名関数 | |
val square4: (Int) -> Int = fun(i: Int): Int { | |
return i * i | |
} | |
// 無名関数 省略バージョン | |
val square5: (Int) -> Int = fun(i: Int) = i * i | |
// p87 ラムダ式の補足 | |
// https://gist.github.com/ohtsuchi/6473a1a6e2e3e2d515273f9a9dee309e | |
// p87 ラムダ式の補足 戻り値の型 | |
// https://kotlinlang.org/docs/reference/lambdas.html#anonymous-functions | |
// p87 ラムダ式の補足 引数リストの () | |
// https://kotlinlang.org/docs/reference/multi-declarations.html#destructuring-in-lambdas-since-11 | |
} | |
// p92 インライン関数 | |
inline fun log(debug: Boolean = true, message: () -> String) { | |
if (debug) { | |
println(message()) | |
} | |
} | |
// p94 crossinline | |
inline fun getCounterInlined(crossinline next: (Int) -> Int): () -> Int { | |
var cnt: Int = 0 | |
return { | |
cnt = next(cnt) | |
cnt | |
} | |
} | |
// p95 非ローカルリターンとラベルへのリターン | |
// 文字列を走査するインライン関数 | |
inline fun forEach(str: String, f: (Char) -> Unit) { | |
for (c in str) { | |
f(c) | |
} | |
} | |
// p95 非ローカルリターンの例 | |
fun containsDigit1(str: String): Boolean { | |
forEach(str) { | |
if (it.isDigit()) | |
return true | |
} | |
println("containsDigit1") | |
return false | |
} | |
// p96 ラベルへのリターン | |
fun containsDigit2(str: String): Boolean { | |
var result = false | |
forEach(str) here@ { | |
if (it.isDigit()) { | |
result = true | |
return@here | |
} | |
} | |
println("containsDigit2") | |
return result | |
} | |
// p96 関数名を指定したリターン | |
fun containsDigit3(str: String): Boolean { | |
var result = false | |
forEach(str) { | |
if (it.isDigit()) { | |
result = true | |
return@forEach | |
} | |
} | |
println("containsDigit3") | |
return result | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment