读《Go并发编程实战》第4章 流程控制方式

简介:

   一个网站的用户管理中,一般用户都会起一个昵称,当然用户A和用户B的昵称有可能相同,我们就使用类型为map[string]int的集合来表示,其中string代表用户昵称、int表示昵称相同的人数。

       集合数据内容为:{"chen":20,   "chen长":10,   "春风":5,   "龙ge":13,   "where你are":7}。


§问题1. 从这个集合中找出只包含中文的用户昵称的计数信息

    上面集合中只有用户昵称为“春风”的元素满足条件,其它像“龙ge”、“chen长”、“where你are”都不是只包含中文。像看程序实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
users := map[string] int { "chen" : 20,  "chen长" : 10,  "春风" : 5,  "龙ge" : 13,  "where你are" : 7}
var targetCount map[string] int  = make(map[string] int )
 
for  name, count := range users {
     matched :=  true
     for  _, v := range name {
         if  v <  '\u4e00'  || v >  '\u9fbf'  {
             matched =  false
             break
         }
     }
     if  matched {
         targetCount[name] = count
     }
}
fmt.Println(targetCount)

解释一下:

第一层for循环遍历users集合,得到昵称(name)和计数(count ):

for namecount := range users{

      // ......

}

第二层循环遍历昵称name字符串中的每个字符,并判断是否有非中文字符:

for _, := range name{

      if v <'\u4e00' || v > '\u9fbf' {  // 该范围下的字符为非中文字符

      }

}

【备注】:

    这里由变量matched充当了标志,当出现非中文字符时,matched被赋为false,并使用break中止第二层循环,然后判断该name是否仅为中文,若是则添加进入targetCountw集合中。


运行结果为:map[春风:5]


§问题2. 从这个集合中找出只包含中文的用户昵称的计数信息,但发现第一个非全中文的用户昵称的时候就停止查找

    这里涉及到map类型的特性问题,当使用for进行遍历users集合时,顺序会出现不确定性,即第一个昵称有可能是“chen”,也有可能是“春风”,也有可能是“龙ge”,总之是不确定的。

    假设第一个昵称是“chen长”时,程序发现它是非全中文的昵称,这时整个程序需要结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for  name, count := range users {
     matched :=  true
     for  _, v := range name {
         if  v <  '\u4e00'  || v >  '\u9fbf'  {
             matched =  false
             break
         }
     }
     if  !matched {
         break
     else  {
         targetCount[name] = count
     }
}
fmt.Println(targetCount)

    这个程序实现与上面基本是大同小异,不同之处在于第一层循环中的matched判断。

    假设在第一层for循环中,第一次取到的昵称name为“龙ge”,此时第二层for循环中会逐个字符地查看“龙ge”这个字符串,当程序发现“龙ge”是非全中文时,matched标志被置为false,同时跑出第二层循环,然后在第一层循环中问:“取到的昵称‘龙ge’是否为全中文?”,结果不是,于是按照题目要求就break掉程序并时跳出第一层循环。


    这里如果您多运行一下程序,就会发现结果有可能是不同的,有时为map[],有时为map[春风:5]


§问题3. 不使用辅助标识(如上例中的matched)解决§问题2.

    作者这里是让您学习break Label这个东东,所以这里直接引用作者原话了:“我们之前说过,break语句可以与标记(Label)语句一起配合使用。

1
2
3
4
5
6
7
8
9
L:
     for  name, count := range users {
         for  _, v := range name {
             if  v <  '\u4e00'  || v >  '\u9fbf'  {
                  break  L
             }
         }
         targetCount[name] = count
     }

该程序与§问题2程序功能是相同的,只是把标志matched移除掉了。


    一条标记语句可以成为goto语句、break语句和contiune语句的目标。标记语句中的标记只是一个标识符,它可以被置在任何语句的左边以作为这个语句的标签。标记和被标记的语句之间需要用冒号“:”来分隔,即如下所示:

L:

     for name, count := range users{

          // .....

     }

    需要注意的是,标记L也是一个标识符,那么当它在未被使用的时候同样也会报告编译错误。那么怎么使用呢?一种方法就是让它成为break的目标,即上面示例中的break L。

    标签L代码块包含了第一层for循环,第一层for循环包含了第二层for循环,所以当break L时,它是中止整个标签L代码块,所以这里会中止两层for循环。


 对比“§问题2”和“§问题3”的两个代码实现,“§问题3”的代码更简洁一些。


§问题4.  还是解决问题1的事情,只不过要求使用continue语句,即从这个集合中找出只包含中文的用户昵称的计数信息

由于这里没有更多的知识点,所以引用原文:

    实际上,Go语言中的continue语句只能在for语句中使用。continue语句会使直接包含它的那个for循环直接进入下一次迭代,换言之,本次迭代不会执行该continue语句后面那些语句(它们被跳过了)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for  name, count := range users {
     matched :=  true
     for  _, v := range name {
         if  v <  '\u4e00'  || v >  '\u9fbf'  {
             matched =  false
             break
         }
     }
 
     if  !matched {
        continue
     }
     targetCount[name] = count
}

或者

1
2
3
4
5
6
7
8
9
L:
     for  name,count := range users{
         for  _, v := range name{
             if  r <  '\u4e00'  || r >  '\u9fbf' {
                 continue  L
             }
         }
         targetCount[name] = count
     }


OK,在读这个章节时,只是感觉这个例子有点意思,所以分享给大家 :)


     本文转自qingkechina 51CTO博客,原文链接:http://blog.51cto.com/qingkechina/1983333,如需转载请自行联系原作者





相关文章
|
3月前
|
Go 调度 开发者
Go语言中的并发编程:深入理解与实践###
探索Go语言在并发编程中的独特优势,揭秘其高效实现的底层机制。本文通过实例和分析,引导读者从基础到进阶,掌握Goroutines、Channels等核心概念,提升并发处理能力。 ###
|
1月前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
2月前
|
存储 Go 开发者
Go语言中的并发编程与通道(Channel)的深度探索
本文旨在深入探讨Go语言中并发编程的核心概念和实践,特别是通道(Channel)的使用。通过分析Goroutines和Channels的基本工作原理,我们将了解如何在Go语言中高效地实现并行任务处理。本文不仅介绍了基础语法和用法,还深入讨论了高级特性如缓冲通道、选择性接收以及超时控制等,旨在为读者提供一个全面的并发编程视角。
|
2月前
|
安全 Serverless Go
Go语言中的并发编程:深入理解与实践####
本文旨在为读者提供一个关于Go语言并发编程的全面指南。我们将从并发的基本概念讲起,逐步深入到Go语言特有的goroutine和channel机制,探讨它们如何简化多线程编程的复杂性。通过实例演示和代码分析,本文将揭示Go语言在处理并发任务时的优势,以及如何在实际项目中高效利用这些特性来提升性能和响应速度。无论你是Go语言的初学者还是有一定经验的开发者,本文都将为你提供有价值的见解和实用的技巧。 ####
|
2月前
|
Go 调度 开发者
Go语言中的并发编程:深入理解goroutines和channels####
本文旨在探讨Go语言中并发编程的核心概念——goroutines和channels。通过分析它们的工作原理、使用场景以及最佳实践,帮助开发者更好地理解和运用这两种强大的工具来构建高效、可扩展的应用程序。文章还将涵盖一些常见的陷阱和解决方案,以确保在实际应用中能够避免潜在的问题。 ####
|
2月前
|
安全 Go 数据处理
Go语言中的并发编程:掌握goroutine和channel的艺术####
本文深入探讨了Go语言在并发编程领域的核心概念——goroutine与channel。不同于传统的单线程执行模式,Go通过轻量级的goroutine实现了高效的并发处理,而channel作为goroutines之间通信的桥梁,确保了数据传递的安全性与高效性。文章首先简述了goroutine的基本特性及其创建方法,随后详细解析了channel的类型、操作以及它们如何协同工作以构建健壮的并发应用。此外,还介绍了select语句在多路复用中的应用,以及如何利用WaitGroup等待一组goroutine完成。最后,通过一个实际案例展示了如何在Go中设计并实现一个简单的并发程序,旨在帮助读者理解并掌
|
2月前
|
安全 Java Go
Go语言中的并发编程:掌握goroutine与通道的艺术####
本文深入探讨了Go语言中的核心特性——并发编程,通过实例解析goroutine和通道的高效使用技巧,旨在帮助开发者提升多线程程序的性能与可靠性。 ####
|
2月前
|
Go 开发者
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念,重点介绍了goroutines和channels的工作原理及其在实际开发中的应用。文章通过实例演示如何有效地利用这些工具来编写高效、可维护的并发程序,旨在帮助读者理解并掌握Go语言在处理并发任务时的强大能力。 ####
|
2月前
|
算法 安全 程序员
Go语言的并发编程:深入理解与实践####
本文旨在探讨Go语言在并发编程方面的独特优势及其实现机制,通过实例解析关键概念如goroutine和channel,帮助开发者更高效地利用Go进行高性能软件开发。不同于传统的摘要概述,本文将以一个简短的故事开头,引出并发编程的重要性,随后详细阐述Go语言如何简化复杂并发任务的处理,最后通过实际案例展示其强大功能。 --- ###
|
2月前
|
存储 安全 Go
Go 语言以其高效的并发编程能力著称,主要依赖于 goroutines 和 channels 两大核心机制
Go 语言以其高效的并发编程能力著称,主要依赖于 goroutines 和 channels 两大核心机制。本文介绍了这两者的概念、用法及如何结合使用,实现任务的高效并发执行与数据的安全传递,强调了并发编程中的注意事项,旨在帮助开发者更好地掌握 Go 语言的并发编程技巧。
36 2