Dart【06】generator生成器函数

2024-08-20 21:28

本文主要是介绍Dart【06】generator生成器函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是生成器函数

Dart生成器函数 (generator) 可以渐进的返回一个值的序列。

Dart内置了两种生成器函数的支持:

同步生成器(sync*):返回一个Iterable对象。
异步生成器(async*):返回一个Stream对象。

同步生成器

使用同步生成器修饰的函数返回的是迭代器Iterable

Iterable主要使用iterator的两个方法moveNext()currentcurrent代表了当前元素,moveNext()将迭代器推进到迭代的下一个元素。

用一段代码展示如何使用同步生成器:

Iterable<int> naturalsTo(int n) sync* {int k = 0;while (k < n) yield k++;
}

测试代码:

void main() {Iterable<int> sequence = naturalsTo(5);print("Starting...");for (int value in sequence) {print(value);}print("DONE");
}

输出如下:

Starting…
0
1
2
3
4
DONE

代码解读:

上面示例中的naturalsTo函数就是使用同步生成器修饰的函数,首先在函数方法体花括号前加入sync*关键字,然后使用yield关键字进行值的返回。

上面的代码示例yield关键字向迭代器序列依次添加了五个值。

看到这里你可能有点疑问,函数返回值不是return吗?yield是干嘛的?

yield和yield*

yield的作用:

yield向周围sync*函数的迭代器中添加一个值。就像return,但不会终止函数。

上面的代码示例yield关键字向迭代器序列依次添加了五个值。

yield功能类似的还有一个关键字yield*yield*只是一种简化写法。如果生成器是递归的,可以使用 yield* 来提高其性能。

用两段代码示例来展示yield*是如何简化代码的:

这是一段没有使用yield*的代码:

void main() {for (int i in numbersDownFrom(3)) {print('$i');}
}Iterable<int> numbersDownFrom(int n) sync* {if (n != 0) {yield n;for (var val in numbersDownFrom(n - 1)) {yield val;}}
}

输出如下:

3
2
1

 for (var val in numbersDownFrom(n - 1)) {yield val;}

这段代码是函数的递归调用,代码流程完全是同步的,你可能要花上一点时间阅读一下代码,你就能理解这段代码做了什么事情。

接下来我们用yield*来简化这段代码:

void main() {for (int i in numbersDownFrom(3)) {print('$i');}
}Iterable<int> numbersDownFrom(int n) sync* {if (n != 0) {yield n;yield* numbersDownFrom(n - 1);}
}

输出如下:

3
2
1

两段代码的作用完全一样,你应该已经理解yield*的作用了,就是对For循环+yield的一种简化。

异步生成器

异步生成器async*在原理上和同步生成器完全一样,都是渐进的返回一个值的序列,唯一区别就是同步生成器返回的是迭代器。异步声明器返回的是Stream

关于Stream的详细介绍参考作者之前的文章。

用一段与上面sync*使用方式一样的代码来为你展示如何使用异步生成器async*

Stream<int> naturalsTo(int n) async* {int k = 0;while (k < n) yield k++;
}

测试代码:

void main() async{Stream<int> sequence = naturalsTo(5);print("Starting...");await for (int value in sequence) {print(value);}print("DONE");
}

输出如下:

Starting…
0
1
2
3
4
DONE

async*sync*工作原理完全一致,如果你对asyncawait for有疑问,参考作者之前的文章。

sync,sync*,async,async*

文章看到这里对异步的全部介绍已经结束了,用一张图片来帮助你记忆sync,sync*,async,async*的区别。

这篇关于Dart【06】generator生成器函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1091219

相关文章

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

kotlin的函数forEach示例详解

《kotlin的函数forEach示例详解》在Kotlin中,forEach是一个高阶函数,用于遍历集合中的每个元素并对其执行指定的操作,它的核心特点是简洁、函数式,适用于需要遍历集合且无需返回值的场... 目录一、基本用法1️⃣ 遍历集合2️⃣ 遍历数组3️⃣ 遍历 Map二、与 for 循环的区别三、高

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st

MySQL中COALESCE函数示例详解

《MySQL中COALESCE函数示例详解》COALESCE是一个功能强大且常用的SQL函数,主要用来处理NULL值和实现灵活的值选择策略,能够使查询逻辑更清晰、简洁,:本文主要介绍MySQL中C... 目录语法示例1. 替换 NULL 值2. 用于字段默认值3. 多列优先级4. 结合聚合函数注意事项总结C

Java8需要知道的4个函数式接口简单教程

《Java8需要知道的4个函数式接口简单教程》:本文主要介绍Java8中引入的函数式接口,包括Consumer、Supplier、Predicate和Function,以及它们的用法和特点,文中... 目录什么是函数是接口?Consumer接口定义核心特点注意事项常见用法1.基本用法2.结合andThen链

MySQL 日期时间格式化函数 DATE_FORMAT() 的使用示例详解

《MySQL日期时间格式化函数DATE_FORMAT()的使用示例详解》`DATE_FORMAT()`是MySQL中用于格式化日期时间的函数,本文详细介绍了其语法、格式化字符串的含义以及常见日期... 目录一、DATE_FORMAT()语法二、格式化字符串详解三、常见日期时间格式组合四、业务场景五、总结一、

golang panic 函数用法示例详解

《golangpanic函数用法示例详解》在Go语言中,panic用于触发不可恢复的错误,终止函数执行并逐层向上触发defer,最终若未被recover捕获,程序会崩溃,recover用于在def... 目录1. panic 的作用2. 基本用法3. recover 的使用规则4. 错误处理建议5. 常见错