Li Kai

  • 主页
  • 所有文章
文章分类 友情链接 关于我

Li Kai

  • 主页
  • 所有文章

Golang高级教程(一)for-range, switch, select使用

2020-02-03

本文简单介绍一下golang中,for-range,switch,select的使用。

1. for-range使用

1.1 for-range地址的坑

for-range的坑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import "fmt"

type Test struct {
Name string
Age int
}

func main() {
testList := []Test{
{"test1", 10},
{"test2", 11},
{"test3", 12},
{"test4", 13},
}

var newTestList []*Test

for _, v := range testList {
newTestList = append(newTestList, &v)
}

for _, v := range newTestList {
fmt.Println(v)
}
}

上述代码是想将一个数组元素的地址,存到另外一个数组。然而实际的结果输出如下所示,

1
2
3
4
5
➜  ~ go run main.go
&{test4 13}
&{test4 13}
&{test4 13}
&{test4 13}

从结果看,与我们预期的不一样,这是什么原因呢?稍等,我稍微改一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import "fmt"

type Test struct {
Name string
Age int
}

func main() {
testList := []Test{
{"test1", 10},
{"test2", 11},
{"test3", 12},
{"test4", 13},
}

var newTestList []*Test

for _, v := range testList {
tmpVal := v //添加这一行code
newTestList = append(newTestList, &tmpVal)
}

for _, v := range newTestList {
fmt.Println(v)
}
}

结果如下:

1
2
3
4
5
➜  ~ go run main.go
&{test1 10}
&{test2 11}
&{test3 12}
&{test4 13}

这次发现结果如预期了。
现在来解释一下原因:在for range中,变量v只是被声明了一次,每次迭代的值,都赋值给了v,而该变量的地址始终不变,所以他所保存的是新赋予的数值。而在改进的代码中,我们将v赋予一个新的变量tmpVal,这样通过拷贝数据,每次都能把对应的数值地址记录。

上面的问题还有一种解决方法,直接引用数据的内存,这个方法比较好,不需要开辟新的内存空间,看代码:

1
2
3
for k,_ := range u{
n = append(n, &u[k])
}

1.2 for-range修改变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import "fmt"

type Test struct {
Name string
Age int
}

func main() {
testList := []Test{
{"test1", 10},
{"test2", 11},
{"test3", 12},
{"test4", 13},
}

for _, v := range testList {
v.Age = 10
}
for _, v := range testList {
fmt.Println(v)
}
}

输出结果如下:

1
2
3
4
5
➜  ~ go run main.go
&{test1 10}
&{test2 11}
&{test3 12}
&{test4 13}

你会发现,数值并没有改变,正确的代码如下:

1
2
3
for k, _ := range testList{
testList[k].age = 10
}

1.3 for-range是否会有死循环

如下代码,在for-range遍历的过程中添加元素,是否会造成死循环呢?

1
2
3
4
5
6
func main() {
v := []int{1, 2, 3}
for i := range v {
v = append(v, i)
}
}

答案是不会,range会对切片做拷贝,新增的数据并不在拷贝内容中,并不会发生死循环。

1.4 for-range map删除元素

在range迭代时,可以删除map中的数据,第一次

1
2
3
4
5
for key := range m {
if key.expired() {
delete(m, key)
}
}

官方的解释如下:

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If map entries that have not yet been reached are removed during iteration, the corresponding iteration values will not be produced. If map entries are created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.

map的迭代顺序是不确定的,并且不能保证每次迭代之间都相同。 如果在迭代过程中删除了尚未到达的映射条目,则不会生成相应的迭代值。 如果映射条目是在迭代过程中创建的,则该条目可能在迭代过程中产生或可以被跳过。 对于创建的每个条目以及从一个迭代到下一个迭代,选择可能有所不同。 如果映射为nil,则迭代次数为0

如果在迭代过程中添加了,以为map存储元素是无序的,所以,有可能存储在已经遍历的位置,此时接下来的迭代,不会打印出新数据。如果存储在还没有遍历的位置,那么接下来的迭代,会打印出新数据。

2. switch的使用

用法如下,switch是按顺序进行匹配,如果都匹配不上的时候,执行default。

1
2
3
4
5
6
7

switch a {
case 10:
fmt.Println("Input is 10")
default:
fmt.Println("input is not matched")
}

3. select的使用

select是用在channel中,select如果匹配上多个,随机选择执行一个,举例分析如下:

1
2
3
4
5
6
select {
case <- channel1:
fmt.Println("Receive data from channel1")
case <- channel2:
fmt.Println("Receive data from channel2")
}

上述代码没有default,所以当没有数据发送给channel的时候,就会block在那,如果不想block,需要加default

1
2
3
4
5
6
7
8
select {
case <- channel1:
fmt.Println("Receive data from channel1")
case <- channel2:
fmt.Println("Receive data from channel2")
default:
fmt.Println("Don't receive any data")
}

参考

  • https://mp.weixin.qq.com/s/G7z80u83LTgLyfHgzgrd9g
  • golang

扫一扫,分享到微信

微信分享二维码
Golang高级教程(二)类型断言
Kubernetes容器安全之Apparmor
  1. 1. 1. for-range使用
    1. 1.1. 1.1 for-range地址的坑
    2. 1.2. 1.2 for-range修改变量
    3. 1.3. 1.3 for-range是否会有死循环
    4. 1.4. 1.4 for-range map删除元素
  2. 2. 2. switch的使用
  3. 3. 3. select的使用
收藏文章
登录
表情删除后不可恢复,是否删除
取消
确定
图片正在上传,请稍后...
取消上传
评论内容为空!
还没有评论,快来抢沙发吧!
  • 最新评论
该评论已关闭!
likai博客正在使用畅言云评
去社区看看吧
去热评看看吧
  • 手把手教你如何用golang实现一个timewheel时间轮 | LiKai的博客
    手把手教你如何用golang实现一个timewheel时间轮 | LiKai的博客
  • Golang高级教程(二)类型断言 | LiKai的博客
    Golang高级教程(二)类型断言 | LiKai的博客
  • 算法(二)深度优先搜索DFS | LiKai的博客
    算法(二)深度优先搜索DFS | LiKai的博客
  • 数据结构-队列 | LiKai的博客
    数据结构-队列 | LiKai的博客
  • 手把手教你如何用golang实现一个timewheel时间轮 | LiKai的博客
  • Golang高级教程(二)类型断言 | LiKai的博客
  • 算法(二)深度优先搜索DFS | LiKai的博客
  • 数据结构-队列 | LiKai的博客
热评话题
  • 数据结构-队列 | LiKai的博客
  • SQL基础教程(四) | LiKai的博客
  • Golang高级教程(一)for-range, switch, select使用 | LiKai的博客
  • Python高级用法 | LiKai的博客
  • 算法(三)二分查找 | LiKai的博客
  • 算法(五)回溯 | LiKai的博客
  • 算法(八)最短路径 | LiKai的博客
关闭
按钮 内容不能为空!
立刻说两句吧! 查看0条评论
  • 你收到0条新通知
  • 你有0条评论收到赞同
  • 你有0条新回复
  • 本日畅言云评热评新鲜出炉啦!
  • 你有0个任务已完成
  • 你收获0个畅言云评足迹
© 2021 Li Kai
Hexo Theme Yilia by Litten
  • 文章分类
  • 友情链接
  • 关于我

tag:

  • test
  • 数据结构
  • shell
  • 计算机网络
  • 数据库
  • 负载均衡
  • ovn
  • 算法
  • linux
  • kubernetes
  • sql
  • python
  • openstack
  • designate
  • neutron
  • golang
  • timewheel

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 手把手教你如何用golang实现一个timewheel时间轮

    2021-04-04

    #算法#golang#timewheel

  • Golang线程池实现百万级高并发

    2021-03-21

    #golang

  • 基于ECMP的多活负载均衡策略

    2020-12-12

    #负载均衡

  • neutron metadata 服务详解

    2020-10-11

    #openstack#neutron

  • ovn为外部主机提供dhcp服务

    2020-09-20

    #ovn

  • Neutron网络troubleshooting

    2020-09-09

    #openstack#neutron

  • kubernetes中pod的自动伸缩

    2020-04-05

    #kubernetes

  • Golang高级教程(二)类型断言

    2020-02-04

    #golang

  • Golang高级教程(一)for-range, switch, select使用

    2020-02-02

    #golang

  • Kubernetes容器安全之Apparmor

    2020-01-04

    #kubernetes

  • 网络性能测试

    2019-09-19

    #计算机网络

  • 算法(十一)刷题常用语法python/go

    2019-07-18

    #算法#python#golang

  • 算法(十)快速排序

    2019-07-10

    #算法#python#golang

  • 算法(九)记忆化搜索

    2019-06-08

    #算法

  • linux常用指令

    2019-03-31

    #linux

  • OpenStack Designate简介

    2019-03-03

    #openstack#designate

  • 算法(八)最短路径

    2018-12-09

    #算法

  • 算法(七)并查集

    2018-10-21

    #算法

  • 算法(六)二叉树

    2018-09-19

    #算法

  • 算法(五)回溯

    2018-07-19

    #算法

  • Python yield使用

    2018-07-09

    #python

  • 算法(四)前缀和

    2018-07-05

    #算法

  • 算法(三)二分查找

    2018-05-19

    #算法

  • 算法(二)深度优先搜索DFS

    2018-04-20

    #算法

  • Python装饰器

    2018-04-19

    #python

  • Python高级用法

    2018-04-09

    #python

  • 算法(一)单调栈

    2018-03-19

    #算法

  • Python单例模式

    2018-03-08

    #python

  • Python编程规范

    2017-05-09

    #python

  • SQL基础教程(四)

    2017-04-19

    #数据库#sql

  • SQL基础教程(三)

    2017-04-11

    #数据库#sql

  • SQL基础教程(二)

    2017-03-24

    #数据库#sql

  • SQL基础教程(一)

    2017-03-19

    #数据库#sql

  • 9.计算机网络-QOS

    2016-08-19

    #计算机网络

  • 8.计算机网络-网络安全(下)

    2016-08-08

    #计算机网络

  • 7.计算机网络-网络安全(上)

    2016-08-01

    #计算机网络

  • 6.计算机网络-应用层

    2016-07-27

    #计算机网络

  • 5.计算机网络-传输层

    2016-07-24

    #计算机网络

  • 4.计算机网络-网络层

    2016-07-22

    #计算机网络

  • 3.计算机网络-数据链路层

    2016-07-17

    #计算机网络

  • 2.计算机网络-物理层

    2016-07-14

    #计算机网络

  • 1.计算机网络概述

    2016-07-09

    #计算机网络

  • Hash算法实现之MD5

    2016-04-09

    #算法

  • 数据结构-链表

    2016-04-02

    #数据结构

  • 数据结构-队列

    2016-04-01

    #数据结构

  • 数据结构-栈

    2016-03-31

    #数据结构

  • Shell基础

    2016-03-27

    #shell

  • Hello World

    2016-03-24

    #test

  • 我的博客园
  • 我的CSDN1
  • 我的CSDN2
李凯
研究生毕业于北邮
现就职于腾讯

一名奋斗在
OpenStack(Python)
Kubernetes(Golang)
的搬运工