他山之石,Kotlin/Dart对比学,高阶函数的定义与使用

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,这一期就此完结。

相关推荐
guoruijun_2012_45 分钟前
fastadmin多个表crud连表操作步骤
android·java·开发语言
Winston Wood6 分钟前
一文了解Android中的AudioFlinger
android·音频
一头小火烧2 小时前
flutter打包签名问题
flutter
sunly_2 小时前
Flutter:异步多线程结合
flutter
AiFlutter2 小时前
Flutter网络通信-封装Dio
flutter
B.-2 小时前
Flutter 应用在真机上调试的流程
android·flutter·ios·xcode·android-studio
有趣的杰克2 小时前
Flutter【04】高性能表单架构设计
android·flutter·dart
大耳猫7 小时前
主动测量View的宽高
android·ui
帅次10 小时前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
枯骨成佛11 小时前
Android中Crash Debug技巧
android