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

相关推荐
sun0077002 小时前
android ndk编译valgrind
android
AI视觉网奇3 小时前
android studio 断点无效
android·ide·android studio
jiaxi的天空3 小时前
android studio gradle 访问不了
android·ide·android studio
No Silver Bullet4 小时前
android组包时会把从maven私服获取的包下载到本地吗
android
catchadmin4 小时前
PHP serialize 序列化完全指南
android·开发语言·php
星秋Eliot5 小时前
Flutter多线程
flutter·async/await·isolate·flutter 多线程
tangweiguo030519876 小时前
Kable使用指南:Android BLE开发的现代化解决方案
android·kotlin
农夫三拳_有点甜8 小时前
Flutter Assets & Media
flutter
00后程序员张8 小时前
iOS App 混淆与资源保护:iOS配置文件加密、ipa文件安全、代码与多媒体资源防护全流程指南
android·安全·ios·小程序·uni-app·cocoa·iphone
柳岸风10 小时前
Android Studio Meerkat | 2024.3.1 Gradle Tasks不展示
android·ide·android studio