Kotlin/Dart的高阶函数有哪些区分
前言
函数式编程大家都不陌生了,但是为什么 Dart 的函数与 Kotlin 的函数表现与写法有这么大的差异?
其实叫法大家都是函数,高阶语言的特性可以把函数当做参数,变量,返回值等,也称之为高阶函数,在 Dart 与 Kotlin 中其实他们的使用思路是一致的。只是写法不同。
既然如此,那么高阶函数的扩展 DSL 等特性,如果 Kotlin 可以实现,在 Dart 中能不能实现呢?
话不多说,直接开始吧!
一、Kotlin 的高阶函数
Kotlin的函数是比较简单的:
kotlin
//Kotlin 中函数类型的语法规则
(String,Int) -> Unit
//或者如下有返回值
() -> Int
参数和返回值,一看就懂。
我们用一个类中的方法,定义两个高阶函数用于回调处理的数据:
kotlin
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 的方式回调。
kotlin
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
}
}
定义对应的接口回调:
kotlin
interface ICompress {
fun onSuccess(srcPath: String, resultPath: String)
fun onError(error: String)
fun start()
}
定义自定义的接口回调与桥接类
kotlin
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的入口:
kotlin
fun NetTest.setCompressDsl(init: CompressImpl.() -> Unit) {
val listener = CompressImpl()
init(listener)
this.setCompress(listener)
}
使用的:
kotlin
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")
}
}
}
结果:
先调用的扩展方法的回调,后面打印的时候DSL的回调方法。
二、Dart 的高阶函数
Dart的函数概念与 Kotlin 类似,只是定义的方式不同
dart
//Dart 中的函数类型的语法规则
void Function(String,int)
//或者如下带返回值
Strign Function()
那么我们用同样的方式定义代码为:
javascript
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 的方式回调接口的处理也是一样的效果:
scss
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);
}
}
使用:
scss
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")
});
});
效果:
后记
其实他们的区别就是 it 和 this 的区别:
kotlin
//这里的 `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 中应用特别广泛。
例如:
javascript
typedef ComprerssSuccess = void Function(String srcPath, String resultPath);
class NetTest {
void start({required ComprerssSuccess onSuccess, required Function(String error) onError}) {}
}
其实在 Kotlin 中也可以这么用,只是我们用的少而已
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,这一期就此完结。