go中如何更好的迭代
三种迭代方式
有如下三种迭代的写法:
- 回调函数方式迭代
- 通过Next()方法迭代。参照python 迭代器的概念,自定义Next()方法来迭代
- 通过channel实现迭代。
假设实现迭代从[2, max],打印出偶数。
func printEvenNumbers(max int) {
if max < 0 {
log.Fatalf("'max' is %d, should be >= 0", max)
}
for i := 2; i <= max; i += 2 {
fmt.Printf("%d\n", i)
}
}
回调函数的做法
// 将迭代的数值传递到回调函数
func printEvenNumbers(max int) {
err := iterateEvenNumbers(max, func(n int) error {
fmt.Printf("%d\n", n)
return nil
})
if err != nil {
log.Fatalf("error: %s\n", err)
}
}
// 实际的迭代的结果,接受一个回调函数,由回调函数处理
func iterateEvenNumbers(max int, cb func(n int) error) error {
if max < 0 {
return fmt.Errorf("'max' is %d, must be >= 0", max)
}
for i := 2; i <= max; i += 2 {
err := cb(i)
if err != nil {
return err
}
}
return nil
}
Next()方法的迭代
// Next()方法放在for循环体之后,通过返回布尔值来控制是否迭代完毕
func (i *EvenNumberIterator) Next() bool
// Value()方法返回当次迭代的值
func (i *EvenNumberIterator) Value() int
例子
package main
import (
"fmt"
"log"
)
// To run:
// go run next.go
// EvenNumberIterator generates even number
type EvenNumberIterator struct {
max int
currValue int
err error
}
// NewEvenNumberIterator creates new number iterator
func NewEvenNumberIterator(max int) *EvenNumberIterator {
var err error
if max < 0 {
err = fmt.Errorf("'max' is %d, should be >= 0", max)
}
return &EvenNumberIterator{
max: max,
currValue: 0,
err: err,
}
}
// Next advances to next even number. Returns false on end of iteration.
func (i *EvenNumberIterator) Next() bool {
if i.err != nil {
return false
}
i.currValue += 2
return i.currValue <= i.max
}
// Value returns current even number
func (i *EvenNumberIterator) Value() int {
if i.err != nil || i.currValue > i.max {
panic("Value is not valid after iterator finished")
}
return i.currValue
}
// Err returns iteration error.
func (i *EvenNumberIterator) Err() error {
return i.err
}
func printEvenNumbers(max int) {
iter := NewEvenNumberIterator(max)
for iter.Next() {
fmt.Printf("n: %d\n", iter.Value())
}
if iter.Err() != nil {
log.Fatalf("error: %s\n", iter.Err())
}
}
func main() {
fmt.Printf("Even numbers up to 8:\n")
printEvenNumbers(8)
fmt.Printf("Even numbers up to 9:\n")
printEvenNumbers(9)
fmt.Printf("Error: even numbers up to -1:\n")
printEvenNumbers(-1)
}
chan方式迭代
// 定义一个返回channel的函数
func generateEvenNumbers(max int) chan IntWithError
// IntWithError struct
type IntWithError struct {
Int int
Err error
}
// 调用方法,range方法可以接chan遍历的特性
func printEvenNumbers(max int) {
for val := range generateEvenNumbers(max) {
if val.Err != nil {
log.Fatalf("Error: %s\n", val.Err)
}
fmt.Printf("%d\n", val.Int)
}
}
// 完整generateEvenNumbers
func generateEvenNumbers(max int) chan IntWithError {
ch := make(chan IntWithError)
go func() {
defer close(ch)
if max < 0 {
ch <- IntWithError{
Err: fmt.Errorf("'max' is %d and should be >= 0", max),
}
return
}
for i := 2; i <= max; i += 2 {
ch <- IntWithError{
Int: i,
}
}
}()
return ch
}
例子:
package main
import (
"fmt"
"log"
)
// To run:
// go run channel.go
// IntWithError combines an integer value and an error
type IntWithError struct {
Int int
Err error
}
func generateEvenNumbers(max int) chan IntWithError {
ch := make(chan IntWithError)
go func() {
defer close(ch)
if max < 0 {
ch <- IntWithError{
Err: fmt.Errorf("'max' is %d and should be >= 0", max),
}
return
}
for i := 2; i <= max; i += 2 {
ch <- IntWithError{
Int: i,
}
}
}()
return ch
}
func printEvenNumbers(max int) {
for val := range generateEvenNumbers(max) {
if val.Err != nil {
log.Fatalf("Error: %s\n", val.Err)
}
fmt.Printf("%d\n", val.Int)
}
}
func main() {
fmt.Printf("Even numbers up to 8:\n")
printEvenNumbers(8)
fmt.Printf("Even numbers up to 9:\n")
printEvenNumbers(9)
fmt.Printf("Error: even numbers up to -1:\n")
printEvenNumbers(-1)
}
通过context实现cancel停止迭代功能
package main
import (
"context"
"fmt"
"log"
)
// To run:
// go run channel-cancellable.go
// IntWithError combines an integer value and an error
type IntWithError struct {
Int int
Err error
}
func generateEvenNumbers(ctx context.Context, max int) chan IntWithError {
ch := make(chan IntWithError)
go func() {
defer close(ch)
if max < 0 {
ch <- IntWithError{
Err: fmt.Errorf("'max' is %d and should be >= 0", max),
}
return
}
for i := 2; i <= max; i += 2 {
if ctx != nil {
// if context was cancelled, we stop early
select {
case <-ctx.Done():
return
default:
}
}
ch <- IntWithError{
Int: i,
}
}
}()
return ch
}
func printEvenNumbersCancellable(max int, stopAt int) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ch := generateEvenNumbers(ctx, max)
for val := range ch {
if val.Err != nil {
log.Fatalf("Error: %s\n", val.Err)
}
if val.Int > stopAt {
cancel()
// notice we keep going in order to drain the channel
continue
}
// process the value
fmt.Printf("%d\n", val.Int)
}
}
func main() {
fmt.Printf("Even numbers up to 20, cancel at 8:\n")
printEvenNumbersCancellable(20, 8)
}
总结:
- 回调方式实现起来最简单但是语法很别扭
- Next()方法实现最困难,但是对调用方很友好,标准库里运用了这种复杂写法
- channel的实现很好,对系统资源的消耗最昂贵,channel应该与goroutine搭配使用,否则尽量不用
go中如何更好的迭代的更多相关文章
- 编写高质量代码改善C#程序的157个建议——建议31:在LINQ查询中避免不必要的迭代
建议31:在LINQ查询中避免不必要的迭代 无论是SQL查询还是LINQ查询,搜索到结果立刻返回总比搜索完所有的结果再将结果返回的效率要高. 示例代码: class MyList : IEnumera ...
- iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式
iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式 说明: 1)该文简短介绍在iOS开发中遍历字典.数组和集合的几种常见方式. 2)该文对应的代码可以在下面的地址获得:https:// ...
- 如何在MySQL中获得更好的全文搜索结果
如何在MySQL中获得更好的全文搜索结果 很多互联网应用程序都提供了全文搜索功能,用户可以使用一个词或者词语片断作为查询项目来定位匹配的记录.在后台,这些程序使用在一个SELECT 查询中的LIKE语 ...
- caffe中在某一层获得迭代次数的方法以及caffe编译时报错 error: 'to_string' is not a member of 'std'解决方法
https://stackoverflow.com/questions/38369565/how-to-get-learning-rate-or-iteration-times-when-define ...
- ios-Objective-C中的各种遍历(迭代)方式(转载)
iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式 说明: 1)该文简短介绍在iOS开发中遍历字典.数组和集合的几种常见方式. 2)该文对应的代码可以在下面的地址获得:https:// ...
- 在FL Studio中如何更好地为人声加上混响(进阶教程)
为人声加上混响是我们在处理人声过程中必不可少的一步.然而,除了直接在人声混音轨道加上混响插件进行调节以外,这里还有更为细节的做法可以达到更好的效果. 步骤一:使用均衡器 在为人声加上混响之前,我们应该 ...
- 【论文阅读】Beyond OCR + VQA: 将OCR融入TextVQA的执行流程中形成更鲁棒更准确的模型
论文题目:Beyond OCR + VQA: Involving OCR into the Flow for Robust and Accurate TextVQA 论文链接:https://dl.a ...
- JAVA中的for-each循环与迭代
在学习java中的collection时注意到,collection层次的根接口Collection实现了Iterable<T>接口(位于java.lang包中),实现这个接口允许对象成为 ...
- 让Redis在你的系统中发挥更大作用的几点建议
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/105.html?1455868313 Redis在很多方面与其他数据库解决 ...
随机推荐
- PATA1062 Talent and Virtue
技术要点就是,一个是cmp函数的书写,首先应该分清楚排序关系,然后按照顺序依次排下去. 还有这里有一个巧妙点就是,在结构体中加入了类别这个标签. 学会抽象分类解决,排序比较函数cmp本质工作就是比较结 ...
- [SDOi2012]Longge的问题(洛谷 2303)
题目描述 Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题.现在问题来了:给定一个整数N,你需要求出∑gcd(i, N)(1<=i <=N). 输入格式 一个整数,为N. ...
- 第01组 Alpha冲刺(6/6)
队名:007 组长博客: https://www.cnblogs.com/Linrrui/p/11914337.html 作业博客: https://edu.cnblogs.com/campus/fz ...
- Linux上安装git并在gitlab上建立对应的项目
1.CentOS上面安装git我所用的CentOS为CentOS6.5,其他版本没有测试. yum install git 安装之后查看git版本信息 git --version 2.配置git信息g ...
- json for modern c++(nlohmann json)使用小计
前言 一开始使用jsoncpp,但是jsoncpp已经不更新了,nlohmann还在更新,并且jsoncpp做过一次大的版本升级,导致api不兼容,以前使用过的工程代码不能很好的升级到新的版本,并且j ...
- 写代码注意了,打死都不要用 User 这个单词
阅读本文大概需要 4 分钟. 原文:http://t.cn/Eau2d0h 译文:http://21cto.com/article/2093 当你意识到你在项目开始时做的轻量.简单的设想竟然完全错了时 ...
- 【Kubernetes学习之三】Kubernetes分布式集群架构
环境 centos 7 一.Kubernetes分布式集群架构1.Kubernetes服务注册和服务发现问题怎么解决的?每个服务分配一个不变的虚拟IP+端口, 系统env环境变量里有每个服务的服务名称 ...
- [原创] C#编程规范工具介绍
1.目标 代码编写规范.整齐.整洁.可读. 无错误 无警告 2.排版 安装PowerCommands扩展 “工具”-“扩展管理库”,搜索安装. 设置选中Format document on save和 ...
- [转帖]Kubesphere all-in-one 安装方式.
All-in-One 模式 对于首次接触 KubeSphere 高级版的用户,想寻找一个最快安装和体验 KubeSphere 高级版核心功能的方式,all-in-one 模式支持一键安装 KubeSp ...
- 宝塔webhook配合码云,本地git push 服务器自动pull
emmmm,这其实是一个很简单的一件事情,但是有很多坑,记录一下 先大概讲一下原理吧,就是每次您 push 代码后,都会给远程 HTTP URL 发送一个 POST 请求 更多说明 » 然后在宝塔这边 ...