Kotlin/Dart的高阶函数有哪些差异

前语

函数式编程咱们都不陌生了,可是为什么 Dart 的函数与 Kotlin 的函数体现与写法有这么大的差异?

其实叫法咱们都是函数,高阶语言的特性能够把函数作为参数,变量,返回值等,也称之为高阶函数,在 Dart 与 Kotlin 中其实他们的运用思路是共同的。仅仅写法不同。

既然如此,那么高阶函数的扩展 DSL 等特性,如果 Kotlin 能够完成,在 Dart 中能不能完成呢?

话不多说,直接开端吧!

参考之资,Kotlin/Dart比照学,高阶函数的界说与运用

一、Kotlin 的高阶函数

Kotlin的函数是比较简单的:

//Kotlin 中函数类型的语法规矩
(String,Int) -> Unit
//或许如下有返回值
() -> Int

参数和返回值,一看就懂。

咱们用一个类中的办法,界说两个高阶函数用于回调处理的数据:

class NetTest : CoroutineScope by MainScope() {
    fun start(onSuccess: (srcPath: String, resultPath: String) -> Unit, onError: (error: String) -> Unit) {
        launch {
            val result = withContext(Dispatchers.IO) {
                delay(500)
                return@withContext Random().nextInt(10)
            }
            when {
                result > 5 -> {
                    onSuccess.invoke("123", "456")
                }
                else -> {
                    onError.invoke("过错的音讯")
                }
            }
        }
    }

这个咱们都懂,那么其实咱们继续用 DSL 的办法回调。

class NetTest : CoroutineScope by MainScope() {
    fun start(onSuccess: (srcPath: String, resultPath: String) -> Unit, onError: (error: String) -> Unit) {
        launch {
            mCallback?.start()
            val result = withContext(Dispatchers.IO) {
                delay(500)
                return@withContext Random().nextInt(10)
            }
            when {
                result > 5 -> {
                    onSuccess.invoke("123", "456")
                    mCallback?.onSuccess("123", "456")
                }
                else -> {
                    onError.invoke("过错的音讯")
                    mCallback?.onError("过错的音讯")
                }
            }
        }
    }
    var mCallback: CompressImpl? = null
    fun setCompress(callback: CompressImpl) {
        this.mCallback = callback
    }
}

界说对应的接口回调:

interface ICompress {
    fun onSuccess(srcPath: String, resultPath: String)
    fun onError(error: String)
    fun start()
}

界说自界说的接口回调与桥接类

class CompressImpl : ICompress {
    private var onSuccess: ((String, String) -> Unit)? = null
    private var onError: ((String) -> Unit)? = null
    private var start: (() -> Unit)? = null
    fun onSuccess(method: (String, String) -> Unit) {
        onSuccess = method
    }
    fun onError(method: (String) -> Unit) {
        onError = method
    }
    fun start(method: () -> Unit) {
        start = method
    }
    override fun onSuccess(srcPath: String, resultPath: String) {
        onSuccess?.invoke(srcPath, resultPath)
    }
    override fun onError(error: String) {
        onError?.invoke(error)
    }
    override fun start() {
        start?.invoke()
    }
}

界说扩展办法,DSL的进口:

fun NetTest.setCompressDsl(init: CompressImpl.() -> Unit) {
    val listener = CompressImpl()
    init(listener)
    this.setCompress(listener)
}

运用的:

        fun dsl() {
            val netTest = NetTest()
            netTest.start(onSuccess = { x, y ->
                YYLogUtils.w("x:$x y:$y")
            }, onError = {
                YYLogUtils.w("it:$it")
            })
            netTest.setCompressDsl {
                start {
                    YYLogUtils.w("开端")
                }
                onSuccess { x, y ->
                    YYLogUtils.w("x:$x y:$y")
                }
                onError {
                    YYLogUtils.w("it:$it")
                }
            }
        }

结果:

参考之资,Kotlin/Dart比照学,高阶函数的界说与运用

先调用的扩展办法的回调,后面打印的时候DSL的回调办法。

二、Dart 的高阶函数

Dart的函数概念与 Kotlin 相似,仅仅界说的办法不同

//Dart 中的函数类型的语法规矩
void Function(String,int)
//或许如下带返回值
Strign Function()

那么咱们用相同的办法界说代码为:

class NetTest {
  void start({required Function(String srcPath, String resultPath) onSuccess, required Function(String error) onError}) {
    Future.delayed(Duration(milliseconds: 500), () {
      int result = Random().nextInt(10);
      if (result > 5) {
        onSuccess("123", "456");
      } else {
        onError("过错的音讯");
      }
    });
  }
  void setCompress(CompressImpl callback) {
    mCallback = callback;
  }
}

咱们相同的用高阶函数界说了回调的结果。

如果咱们想在 Dart 中运用 DSL 的办法回调接口的处理也是相同的作用:

abstract class ICompress {
  void onSuccess(String srcPath, String resultPath);
  void onError(String error);
  void start();
}
class CompressImpl implements ICompress {
  Function(String, String)? _onSuccess;
  Function(String)? _onError;
  Function()? _start;
  void OnSuccess(Function(String, String) method) {
    _onSuccess = method;
  }
  void OnError(Function(String) method) {
    _onError = method;
  }
  void OnStart(Function() method) {
    _start = method;
  }
  @override
  void onSuccess(String srcPath, String resultPath) {
    _onSuccess?.call(srcPath, resultPath);
  }
  @override
  void onError(String error) {
    _onError?.call(error);
  }
  @override
  void start() {
    _start?.call();
  }
}
class NetTest {
  CompressImpl? mCallback;
  void start({required Function(String srcPath, String resultPath) onSuccess, required Function(String error) onError}) {
    mCallback?.start();
    Future.delayed(Duration(milliseconds: 500), () {
      int result = Random().nextInt(10);
      if (result > 5) {
        onSuccess("123", "456");
        mCallback?.onSuccess("123", "456");
      } else {
        onError("过错的音讯");
        mCallback?.onError("过错的音讯");
      }
    });
  }
  void setCompress(CompressImpl callback) {
    mCallback = callback;
  }
}
extension CompressDsl on NetTest {
  void setCompressDsl(void Function(CompressImpl) init) {
    CompressImpl listener = CompressImpl();
    init.call(listener);
    setCompress(listener);
  }
}

运用:

        var test = NetTest();
        test.start(onSuccess: (x, y) {}, onError: (e) {});
        test.setCompressDsl((c) {
        c.OnStart(() => {
            Log.d("开端")
        });
        c.OnSuccess((x, y) => {
            Log.d("x:$x y:$y")
        });
        c.OnError((e) => {
            Log.d("e:$e")
        });
        });

作用:

参考之资,Kotlin/Dart比照学,高阶函数的界说与运用

跋文

其实他们的差异就是 it 和 this 的差异:

//这里的`init(listener)`实际上是调用`CompressImpl`上的扩展函数,其中`listener`作为`this`隐式接收者。这允许在`init`块内部直接访问`CompressImpl`的特点和函数,而无需运用任何前缀。
fun NetTest.setCompressDsl(init: CompressImpl.() -> Unit) {
    val listener = CompressImpl()
    init(listener)  // 在这里,listener 是 implicit receiver
    this.setCompress(listener)
}
//在 Dart 中,没有直接等价于 Kotlin 中的 "implicit receiver" 特性。Dart 的函数传递和 lambda 表达式更直接、传统,没有这种基于扩展函数的隐式接收者概念。在 Dart 中,要操作特定目标的特点或办法,你需求明确引用该目标。
fun NetTest.setCompressDsl(init: (CompressImpl) -> Unit) {
    val listener = CompressImpl()
    init(listener)
    this.setCompress(listener)
}

Kotlin 能够用它的 implicit receiver 特性,把 it 变成 this,到达双 this 的作用,这里很多人也称之为高阶扩展函数,而 Dart 就必须要用 it 去手动的点出来赋值函数的办法,显得不是那么优雅。

其次他们还有很多小技巧相同的地方,比方都能够设置别名,通过 typedef 能够给函数起别名,这一点在 Flutter 中运用特别广泛。

例如:

typedef ComprerssSuccess = void Function(String srcPath, String resultPath);
class NetTest {
  void start({required ComprerssSuccess onSuccess, required Function(String error) onError}) {}
}

其实在 Kotlin 中也能够这么用,仅仅咱们用的少而已

typealias IntOperation = (Int, Int) -> Int
fun performOperation(x: Int, y: Int, operation: IntOperation): Int { return operation(x, y) } val sum: IntOperation = { a, b -> a + b }
val resultSum = performOperation(2, 3, sum)

要不怎么说这个系列叫参考之资呢?我之前也是不了解 Kotlin 还有这功能呢,自己也是跟着学习了一波。

言归正传,理解和掌握函数式思维,不管是 Dart 语法仍是 Kotlin 语法,不管是写代码仍是阅读源码都会更流畅。

那么本期内容就到这里了,如讲的不到位或讹夺的地方,期望同学们能够评论区指出。

由于代码比较简单,本文悉数贴出,如果感觉本文对你有一点点点的启示,还望你能点赞支持一下,你的支持是我最大的动力啦。

Ok,这一期就此结束。

参考之资,Kotlin/Dart比照学,高阶函数的界说与运用