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

相关推荐
还鮟1 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡2 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi002 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil4 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你4 小时前
Android View的绘制原理详解
android
瓜子三百克6 小时前
十、高级概念
flutter
移动开发者1号7 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号7 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best12 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk12 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk