Kotlinは理解し、高階関数を使用します

1.基本的な定義

1.1高階関数とは何ですか

定義により、より高次の関数である値を返す引数または関数としてさらに機能します
Kotlinでは、関数は、関数またはラムダ参照によって表すことができます。
したがって、任意の順序lambdaまたは関数参照の引数または戻り値としてlambda関数機能、または両方が満たされているか、機能の参照は、高次関数です。

1.2ラムダ大会:

:機能に精通してKotlin、あなたが最初のコードラムダ式を読み取る必要があり、我々は最初のような規則の数は場所を知る必要があります
関数が唯一のパラメータとして機能し、使用しているとき、lambda式を関数の対応するパラメータを省略することができるように括弧()
関数の最後のパラメータを使用すると、カッコ内にパラメータリストの外側に書かれた関数のパラメータのラムダ式を使用することができ、種類の関数です。

例如:
str.sumBy( { it.toInt } )
可以省略成
str.sumBy{ it.toInt }

Anko的Context扩展alert函数,可以注意到positiveButton方法第一个参数是text,
第二个参数是监听器lambda表达式,写在了参数列表圆括号外面。
alert("确定删除吗?","Alert") {
    positiveButton("OK") { Log.i(TAG, "你点了确定按钮")}
    negativeButton("Cancel") { Log.i(TAG, "你点了取消按钮") }
}.build().show()

Javaコードに対応する1.3関数型変数

Kotlinでは、変数の型があってもよい函数类型、例えば、次のコードsumの種類は可変であるInt类型predicate変数である函数类型ことを、この変数は関数を表します

声明一个名字为sum的Int类型变量(这个sum变量的类型是Int)
var sum:Int

声明一个名字为predicate的函数类型变量(这个predicate变量的类型是函数)
predicate是一个以Char为参数,返回值为Boolean的函数。
var predicate: (Char) -> Boolean

声明一个以predicate函数为参数的函数(高阶函数),这个函数的返回类型是String
fun filter(predicate: (Char) -> Boolean) :String

让上面这个函数带上接受者,其实就是给String声明了一个扩展函数。
带上了接收者的函数,函数内部可以直接访问String的其他方法属性,相当于函数内部的this就是String
fun String.filter(predicate: (char) -> Boolean) :String

対応する形の参照があることKotlin Java関数ようKotlinと混合するJavaコードは、起動され、すなわちFunction、参照Function1<P, R>のみつのパラメータタイプはR.の戻り値Pの基準型であることを意味します

2.標準の高次機能

高次機能の2.1宣言

で宣言された標準的な高階関数Standard.ktを含む文書、TODOrunwithapplyalsolettakeIftakeUnlessrepeat機能しています。
私たちは、次のような、同様の機能を対比して機能しますrun & withapply & alsotakeIf & takeUnlesslet & 扩展函数版本run

2.2ラン&機能付き

/**
 * Calls the specified function [block] and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

/**
 * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

実行機能のバージョンは、1つの機能の拡張版であり、一つは仕様の通常バージョンである、2つのバージョンを持っている
、コード定義から分かるrun函数とる引数(高階関数)としての機能リファレンスをちょうどこのコードのビットを呼び出す内、戻り値のブロックとブロックのコードブロック。
それは見つけることができるwithrun返されますblock(関数のリファレンス)の戻り値。
:どのような違い
の差が、その後、使用する前に空にし言い渡され、必要に応じて、実行拡張機能があることである扩展函数版本的run函数よりも使いwith函数など、エレガント:

// Yack!
with(webview.settings) {
      this?.javaScriptEnabled = true
      this?.databaseEnabled = true
}
// Nice.
webview.settings?.run {
    javaScriptEnabled = true
    databaseEnabled = true
}

それは見ることができます扩展函数版本的run函数呼び出しが最初webview.settingsが空であるかどうかを判断することができ、または関数呼び出しのボディを入力しないでください前に。

2.3にも適用されます&

/**
 * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
 */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

/**
 * Calls the specified function [block] with `this` value as its argument and returns `this` value.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

applyalso最後に、受信機自体に戻りTコードをより明確に、コードサイズを絞り込み連鎖呼び出しを実現することができる、それらの間の差が使用されている受信機としてので、内部にアクセスすることができそれがパラメータとして渡されますその中に内部必要性の代理受信者applyblockT(也就是apply的接收者本身)applyblockT这个thisalsoTblockalsoblockit(lambda的唯一参数)alsoT

上の使用:
一般的には、lambdaのためのパラメータitの機能は、多くの場面を読んだとして使うのに適して、名前付きパラメータを使用することができますがされit、コードの可読性を高めるために、適切な名前に変更しT、着信block(T)、書き込み値のための機会がより適切な繰り返し文州T変数がたくさんあるため。
主にあれば、ブロックラムダ式を[推奨]、インスタンスの書き込み、インスタンスが宣言されReceiver、場合に主が読み出され、インスタンスは、パラメータを宣言しました
だから、長いも、コードの読み取り動作の長いブロックを使用して、コードブロックライト動作値を適用します。

inline fun <T> T.apply(block: T.() -> Unit): T//对T进行写操作,优先使用apply

tvName.apply {
    text = "Jacky"
    textSize = 20f
}

inline fun <T> T.also(block: (T) -> Unit): T //对T进行读操作 优先使用also

user.also {
    tvName.text = it.name
    tvAge.text = it.age
}

2.4 Let関数

/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

/**
 * Calls the specified function [block] with `this` value as its argument and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)

letこの機能は、ある扩展版本的run函数ような非常に多く、私は上記のコードとは対照的に入れて、両者の差がrunあるblock参数こと1 带run接收者T的函数引用、およびするパラメータとしてその差が呼び出しの使用であるので、内部ポインティング、及びで内部の必要性を指すように内部にはを参照する外部のあなたはのようなものを意味し、内部の使用内部がこれですletblock参数是let的接收者TblockrunblockthisTletblockitTletblockthisTthisActivityletletblockthisActivity实例

run関数が複数のコードブロックを記述するのに適した値を比較し、let関数は、コードブロックをマルチ読み取るのに適しています。

2.4.1も差の戻り値を聞かせて

let戻りblock的返回值also戻り接收者T自身、そう、彼らはチェーンを呼び出すには、本質的に異なっています。
letあなたは似て達成することができますRxJavamap効果

val original = "abc"
// Evolve the value and send to the next chain
original.let {
    println("The original String is $it") // "abc"
    it.reversed() // evolve it as parameter to send to next let
}.let {
    println("The reverse String is $it") // "cba"
    it.length  // can be evolve to other type
}.let {
    println("The length of the String is $it") // 3
}
// Wrong
// Same value is sent in the chain (printed answer is wrong)
original.also {
    println("The original String is $it") // "abc"
    it.reversed() // even if we evolve it, it is useless
}.also {
    println("The reverse String is ${it}") // "abc"
    it.length  // even if we evolve it, it is useless
}.also {
    println("The length of the String is ${it}") // "abc"
}
// Corrected for also (i.e. manipulate as original string
// Same value is sent in the chain 
original.also {
    println("The original String is $it") // "abc"
}.also {
    println("The reverse String is ${it.reversed()}") // "cba"
}.also {
    println("The length of the String is ${it.length}") // 3
}

上記では、それはそうですT.also、我々は簡単に一つの機能ブロックにそれらを組み合わせることができますので、無意味のように。しかし、それについて考える、それはいくつかの利点があります:

これは、同じオブジェクト上に設けることができる非常に明確な分離プロセス、すなわち、小さい機能部の製造
使用前に、それは、非常に強力な自己操作を実現することができチェーン動作ビルダー(ビルダーモード)を達成します

2.5 takeIf&takeUnless

/**
 * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

/**
 * Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (!predicate(this)) this else null
}

これら二つの機能は、条件判断を行うために使用される場合、使用されるtakeIfことがであるpredicate返すように条件true受信機自体が、これらのリターンかどう場合戻すためにnulltakeUnless反対が正確であるpredicateためにfalse戻りそうでなければ、受信機自体を返しますnull

2.6リピート機能

/**
 * Executes the given function [action] specified number of [times].
 *
 * A zero-based index of current iteration is passed as a parameter to [action].
 *
 * @sample samples.misc.ControlFlow.repeat
 */
@kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
    contract { callsInPlace(action) }

    for (index in 0 until times) {
        action(index)
    }
}

この機能は、することですaction繰り返し実行ブロックtimes、二度actionパラメータは、現在実行中であるindex(何度も)。

2.7これまたパラメータ対

あなたがチェックするとT.run関数のシグネチャを、あなたはそれに気づくでしょうT.runちょうど拡張関数呼び出しとしてblock: T.()したがって、すべての範囲は、Tと呼ばれてもよいですthisプログラミングでは、thisほとんどの時間を省略することができます。したがって、上記の例では、我々は可能printlnステートメントを使用$length代わりに${this.length}私は、転送呼び出しthisパラメータを。
しかし、用T.let関数のシグネチャ、あなたはそれがわかりますT.let、パラメータとして自分自身の中に渡し、それがありますblock: (T)だから、それは渡すようなものだlambdaパラメータを。これは、範囲の範囲内で使用することができるit基準となります。だから私は、転送呼び出しitパラメータを。
上から見た、ように見えるT.runので、より優れていることT.letがより隠されたが、これはあるT.letいくつかの微妙な利点の機能は次のとおりです。

T.let比較外部クラスの機能は/メンバーは、与えられた変数の関数は/メンバーは明確に区別提供
thisそれが関数のパラメータとして渡される場合、例えば、ケースを省略することができないitよりthis短く、より明確。
ではT.let、変数は、より良い名前を使用することができます、あなたは切り替えることができますit別の名前に。

stringVariable?.let {
      nonNullString ->
      println("The non null string is $nonNullString")
}

これらの機能の2.8選択は、次のとおりです。

コールチェーンの元の型を保つ(T - > T) 他のタイプへのコールチェーン(T - > R) コールチェーン開始(考えます) コールチェーンアプリケーション条件文
書き込み操作 T.apply {...} T.run {...} (T){...}と T.takeIf / T.takeUnless
マルチリード T.also {...} T.let {...}
436713-5c6f5a2b83364498.png
適切な標準の高階関数を選択するための彼らの必要性によると、

3.高次機能をカスタマイズ

コード3.1デバッグ環境で実行する前に、

//声明:
inline fun debug(code: () -> Unit){
    if (BuildConfig.DEBUG) {
        code() 
    }
}

//用法:
fun onCreate(savedInstanceState: Bundle?) {
    debug {
        showDebugTools();
    }
}

宣言された関数inlineはコンパイル時にインラインコードをコピーして、対応するローカルコールに貼り付けられます、大規模で複雑な関数本体あれば、それ以外の場合は、ボリュームの増加を詰めるだろう、インラインでの使用はお勧めしません。

4.アンコ関連の発表

4.1アンコギャラリーは、標準のダイアログボックスを表示します

alert("确定删除吗?","Alert") {
    positiveButton("OK") { Log.i(TAG, "你点了确定按钮")}
    negativeButton("Cancel") { Log.i(TAG, "你点了取消按钮") }
}.build().show()

4.2アンコライブラリは、いくつかの部分が含まれています。

アンコは、いくつかの部分で構成されています。

  • アンココモンズ:ように意図、ダイアログ、ログおよびのためのヘルパーの完全な軽量ライブラリ。
  • アンコレイアウト:ダイナミックAndroidのレイアウトを記述するための高速かつタイプセーフな方法。
  • アンコのSQLite:AndroidのSQLiteのためのクエリDSLおよびパーサコレクション。
  • アンココルーチン:[kotlinx.coroutines]に基づいて、ユーティリティ

公共の一部:テント、ダイアログ、ログおよび他の高階関数。
レイアウトセクション:動的な拡張機能は、迅速な表示された4.1標準のダイアログボックスとして、レイアウトを追加します。
SQLiteの部品:クエリの解析DSL用のセット
コルーチン部分:コルーチン関連ツール。

4.2.1アンコレイアウト(ウィキ

アンコレイアウトは動的なAndroidのレイアウトを記述するためのDSLです。ここではアンコのDSLで書かれたシンプルなUIは以下のとおりです。

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}

4.2.2アンコのSQLite(ウィキ

あなたは今までAndroidのカーソルを使用してSQLiteのクエリ結果を解析するのに疲れていますか?アンコSQLiteは SQLiteのデータベースで作業を簡素化するためにヘルパーの多くを提供します。

たとえば、ここにあなたが特定の名前を持つユーザーの一覧を取得する方法です。

fun getUsers(db: ManagedSQLiteOpenHelper): List<User> = db.use {
    db.select("Users")
            .whereSimple("family_name = ?", "John")
            .doExec()
            .parseList(UserParser)
}

アンコホームでの詳細な表情

5.リソース

Kotlinの標準機能をマスターする:実行を、また、聞かせてと適用、と
函数掌握Kotlin标准を:実行、また、聞かせてと適用、と
アンコ:https://github.com/Kotlin/anko

ます。https://www.jianshu.com/p/92c7581ab042で再現

おすすめ

転載: blog.csdn.net/weixin_33670713/article/details/91087294