Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Kotlinスタートブック読書勉強会 #4 第6章 第一級オブジェクトとしての関数 (参考資料)
/**
* 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
You can’t perform that action at this time.