Kotlin は高階関数に注意 (7)

Kotlin は高階関数に注意 (7)

Kotlin ノートのデータ型 (1) Kotlin ノートの文字列 (2) Kotlin ノートの演算子 (3) Kotlin ノートの関数 (4) Kotlin ノートのオブジェクト指向 (5) Kotlin ノートの継承、抽象クラス、インターフェース (6)






1. 高階関数

関数は別の関数のパラメーターとして使用するか、値を返すことができます。この関数は「高階関数」です。

2.機能タイプ

Kotlin のすべての関数には「関数型」と呼ばれる型があります. データ型としては,
関数型とデータ型の使用シーンの違いはありません.

//定义计算长方形面积函数
//函数类型(Double, Double) -> Double
fun rectangleArea(width: Double, height: Double): Double {
    
    return width * height
}
//定义计算三角形面积函数
//函数类型(Double, Double) -> Double
fun triangleArea(bottom: Double, height: Double) = 0.5 * bottom * height ②
fun sayHello() {
    
     //函数类型()->Unit ③
print("Hello, World")
}
fun main(args: Array<String>) {
    
    
val getArea: (Double, Double) -> Double = ::triangleArea ④
//调用函数
val area = getArea(50.0, 40.0)print(area) //1000.0
}

3. 関数リテラル

関数型変数は宣言できるのですが、関数型変数はどのようなデータを受け取ることができるのでしょうか? つまり、関数リテラルをどのように表現するかということです
。関数リテラルは次の 3 つの方法で表現できます。

  • 関数参照。定義済みの名前付き関数への参照。関数リテラルとして使用できます。
  • 無名関数。名前のない関数、つまり無名関数も関数リテラルとして使用できます。
  • ラムダ式。ラムダ式は、関数リテラルとして使用できる匿名関数です。
fun calculate(opr: Char): (Int, Int) -> Int {
    
    
//加法函数
fun add(a: Int, b: Int): Int {
    
    
return a + b
}
//减法函数
fun sub(a: Int, b: Int): Int {
    
    
return a - b
}
val result: (Int, Int) -> Int =
when (opr) {
    
    
'+' -> ::add ①
'-' -> ::sub ②
'*' -> {
    
    
//乘法匿名函数
fun(a: Int, b: Int): Int {
    
     
return (a * b)
}
}
else -> {
    
     a, b -> (a / b) } //除法Lambda表达式 ④
}
return result
}
fun main(args: Array<String>) {
    
    
val f1 = calculate('+')println(f1(10, 5)) //调用f1变量 ⑥
val f2 = calculate('-')
println(f2(10, 5))
val f3 = calculate('*')
println(f3(10, 5))
val f4 = calculate('/')
println(f4(10, 5))
}

4.戻り値として機能

fun main(args: Array<String>) {
    
    

    var funName=getFunWithType(2)

    println(funName(1,3))
}
fun getFunWithType(type:Int):(Int,Int)->Int{
    
    
    var functionType:(Int,Int)->Int
    when(type){
    
    
        1-> functionType=fun (a:Int,b:Int):Int=a+b
        else -> functionType={
    
    a,b->a-b}
    }

    return functionType
}

5. パラメータとしての機能

fun main(args: Array<String>) {
    
    
    var funName=getFunWithType(2)
    println(operterFun(funName,4,5))
}
fun operterFun(funName:(Int,Int)->Int,a: Int,b: Int):Int{
    
    
    return funName(a,b)
}
fun getFunWithType(type:Int):(Int,Int)->Int{
    
    
    var functionType:(Int,Int)->Int
    when(type){
    
    
        1-> functionType=fun (a:Int,b:Int):Int=a+b
        else -> functionType={
    
    a,b->a-b}
    }

    return functionType
}

二、ラムダ式

1. ラムダ式の標準構文

{ パラメータ一覧 -> ラムダ本体 }

ラムダ式のパラメータ リストは関数のパラメータ リストに似ていますが、ラムダ式のパラメータ リスト
を囲む括弧はありません。矢印表記はパラメータ リストを Lambda 本体から分離し、Lambda 式は
戻り値の型を宣言する必要はありません。ラムダ式は戻り値を持つことができます. If there is no return statement, the last expression in the Lambda body
is the return value of the Lambda expression. If there is a return statement
.

fun main(args: Array<String>) {
    
    

    var funLa={
    
    a:Int,b:Int-> a+b}

    println(funLa(2,4))

}

2. ラムダ式の簡略化された記述


{a:Int,b:Int-> a+b}は { a, b -> a + b }に簡略化できます

末尾の Lambda 関数の最後のパラメーターが Lambda 式の場合、この Lambda 式を
関数の括弧の後に配置できます。

fun main(args: Array<String>) {
    
    

    //正常调用
//    operterFun(2,3,{a,b->a+b})
    
    //尾随写法
    operterFun(2,3){
    
    a,b->
        a+b
    }
}

fun operterFun(a: Int,b: Int,funName:(Int,Int)->Int):Int{
    
    
    return funName(a,b)
}

ラムダ式のパラメータが 1 つしかなく、そのデータ型がコンテキストに応じて推測できる場合、
このパラメータ宣言は省略でき、暗黙的なパラメータはラムダ本体で使用され、ラムダ式
のパラメータを置き換えます。

fun main(args: Array<String>) {
    
    
    
    operterLa("zyb"){
    
     println(it)}

}


fun operterLa(name:String,funName: (String)->Unit){
    
    
    funName(name)
}

3.ラムダ式とreturn文

return ステートメントは Lambda 式の本体でも使用できます。これにより、プログラムが Lambda 式の本体から飛び出します。

fun main(args: Array<String>) {
    
    

    println(sum(1,2,3,10,3)) //9
    val add = label@ {
    
    
        val a = 1
        val b = 2
        return@label 10
        a + b
    }
//调用Lambda表达式add
    println(add()) //10
}


//累加求和函数
fun sum(vararg num: Int): Int {
    
    
    var total = 0
    num.forEach {
    
    
//        if (it == 10) return -1 //返回最近的函数 ②
        if (it == 10) return@forEach//返回Lambda表达式函数 ③
        total += it
    }
    return total
}

3. クロージャとキャプチャ変数

Closure (クロージャー) は、関数本体の外にある変数にアクセスできる特別な関数です. この変数は、
元のスコープを離れても、関数と共に存在します. この特別な関数は通常、ローカル関数、匿名
関数、または Lambda 式です。

fun makeArray(): (Int) -> Int {
    
     ①
var ary = 0//局部函数捕获变量
fun add(element: Int): Int {
    
     ③
ary += element ④
return ary ⑤
}
return ::add ⑥
}
fun main(args: Array<String>) {
    
    
val f1 = makeArray()println("---f1---")
println(f1(10))//累加ary变量,输出结果是10
println(f1(20))//累加ary变量,输出结果是30
}

4.インライン関数

上位関数では、パラメータが関数型の場合、Lambda 式を受け取ることができ、Lambda 式は
コンパイル時に匿名クラスとしてコンパイルされ、関数が呼び出されるたびにオブジェクトが作成されます。これは、関数によって繰り返し呼び出されます
次に、多くのオブジェクトを作成します。これにより、余分なランタイム オーバーヘッドが発生します。この問題を解決するために、そのような関数をKotlin で
インライン関数として宣言できます。インライン関数がコンパイル時に関数呼び出しコードを生成しないことを確認しますが、各呼び出し関数を関数本体
の実際のコードに置き換えます

1.インライン関数定義

キーワード inline を使用する

inline fun calculatePrint(funN: (Int, Int) -> Int) {
    
    println("${funN(10, 5)}")
}
fun main(args: Array<String>) {
    
    
calculatePrint {
    
     a, b -> a + b } ②
calculatePrint {
    
     a, b -> a - b }}

2. let 関数を使用する

Kotlin では、関数パラメーターが非 null 型として宣言されている場合、null 許容型のパラメーターも受け取ることができますが、実際のパラメーターが実際に
null である場合、重大な問題が発生する可能性があります。したがって、パラメーターを渡す前に、
nullable パラメーターが非 null かどうかを判断する必要があります。

fun main(args: Array<String>) {
    
    


sayNameLength(null)
}


fun sayNameLength(name:String?){
    
    
//    if (name!=null){
    
    
//        println(name.length)
//    }
    name?.let {
    
    println(it.length) }
}

2. with および apply 関数を使用する

オブジェクトに複数のプロパティを設定したり、複数の関数を呼び出したりする必要がある場合は、 with または apply 関数を使用できます。
let 関数と同様に、Kotlin のすべてのオブジェクトはこれら 2 つの関数を使用できます。

with は式の最後の文を返し、apply はオブジェクトを返します。

fun main(args: Array<String>) {
    
    


//sayNameLength(null)


    var name=StringBuilder(0)

    var stringBuilder2=name.apply{
    
    
        append("hello")
        append("  ")
        append("world")

    }

    var stringBuilder3= with(name){
    
    
        this.append("\n")
        this.append("My name is ")
        this.append("zyb")
        "我是with"
    }

    println(name)
    println(stringBuilder2)
    println(stringBuilder3)

## hello  world
## My name is zyb
## hello  world
## My name is zyb
## 我是with
}

おすすめ

転載: blog.csdn.net/baidu_31956557/article/details/109290124