Go语言for range(按照键值循环)遍历操作

Go 语言可以使用 for range 遍历数组、切片、字符串、map 及通道(channel)。通过 for range 遍历的返回值有一定的规律:

数组、切片、字符串返回索引和值。

map 返回键和值。

通道(channel)只返回通道内的值。

遍历数组、切片——获得索引和元素

在遍历代码中,key 和 value 分别代表切片的下标及下标对应的值。下面的代码展示如何遍历切片,数组也是类似的遍历方法:

for key, value := range []int{1, 2, 3, 4} {
  fmt.Printf("key:%d value:%d\n", key, value)
}

代码输出如下:

key:0 value:1
key:1 value:2
key:2 value:3
key:3 value:4

遍历字符串——获得字符

Go 语言和其他语言类似,可以通过 for range 的组合,对字符串进行遍历,遍历时,key 和 value 分别代表字符串的索引(base0)和字符串中的每一个字符。

下面这段代码展示了如何遍历字符串:

var str = "hello 你好"
for key, value := range str {
  fmt.Printf("key:%d value:0x%x\n", key, value)
}

代码输出如下:

key:0 value:0x68
key:1 value:0x65
key:2 value:0x6c
key:3 value:0x6c
key:4 value:0x6f
key:5 value:0x20
key:6 value:0x4f60
key:9 value:0x597d

代码中的 v 变量,实际类型是 rune,实际上就是 int32,以十六进制打印出来就是字符的编码。

遍历map——获得map的键和值

对于 map 类型来说,for range 遍历时,key 和 value 分别代表 map 的索引键 key 和索引对应的值,一般被称为 map 的键值对,因为它们总是一对一对的出现。下面的代码演示了如何遍历 map。

m := map[string]int{
  "hello": 100,
  "world": 200,
}
for key, value := range m {
  fmt.Println(key, value)
}

代码输出如下:

hello 100

world 200

注意

对 map 遍历时,遍历输出的键值是无序的,如果需要有序的键值对输出,需要对结果进行排序。

遍历通道(channel)——接收通道数据

for range 可以遍历通道(channel),但是通道在遍历时,只输出一个值,即管道内的类型对应的数据。

下面代码为我们展示了通道的遍历:

c := make(chan int)
go func() {
  c <- 1
  c <- 2
  c <- 3
  close(c)
}()
for v := range c {
  fmt.Println(v)
}

代码说明如下:

第 1 行创建了一个整型类型的通道。

第 3 行启动了一个 goroutine,其逻辑的实现体现在第 5~8 行,实现功能是往通道中推送数据 1、2、3,然后结束并关闭通道。

这段 goroutine 在声明结束后,在第 9 行马上被并行执行。

从第 11 行开始,使用 for range 对通道 c 进行遍历,其实就是不断地从通道中取数据,直到通道被关闭。

在遍历中选择希望获得的变量

在使用 for range 循环遍历某个对象时,一般不会同时需要 key 或者 value,这个时候可以采用一些技巧,让代码变得更简单。下面将前面的例子修改一下,参考下面的代码示例:

m := map[string]int{
  "hello": 100,
  "world": 200,
}
for _, value := range m {
  fmt.Println(value)
}

代码输出如下:

100

200

在例子中将 key 变成了下画线,那么这里的下画线就是匿名变量。什么是匿名变量?

可以理解为一种占位符。

本身这种变量不会进行空间分配,也不会占用一个变量的名字。

在 for range 可以对 key 使用匿名变量,也可以对 value 使用匿名变量。

再看一个匿名变量的例子:

for key, _ := range []int{1, 2, 3, 4} {
  fmt.Printf("key:%d \n", key)
}

代码输出如下:

key:0
key:1
key:2
key:3

在该例子中,value 被设置为匿名变量,只使用 key,而 key 本身就是切片的索引,所以例子输出索引。

我们总结一下for的功能:

Go 语言的 for 包含初始化语句、条件表达式、结束语句,这 3 个部分均可缺省。

for range 支持对数组、切片、字符串、map、通道进行遍历操作。

在需要时,可以使用匿名变量对 for range 的变量进行选取。

补充:学习-go语言坑之for range

go只提供了一种循环方式,即for循环,在使用时可以像c那样使用,也可以通过for range方式遍历容器类型如数组、切片和映射。但是在使用for range时,如果使用不当,就会出现一些问题,导致程序运行行为不如预期。比如,下面的示例程序将遍历一个切片,并将切片的值当成映射的键和值存入,切片类型是一个int型,映射的类型是键为int型,值为*int,即值是一个地址。

package main
import "fmt"
func main() {
  slice := []int{0, 1, 2, 3}
  myMap := make(map[int]*int)

  for index, value := range slice {
    myMap[index] = &value
  }
  fmt.Println("=====new map=====")
  prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
  for key, value := range myMap {
    fmt.Printf("map[%v]=%v\n", key, *value)
  }
}

运行程序输出如下:

=====new map=====
map[3]=3
map[0]=3
map[1]=3
map[2]=3

由输出可以知道,不是我们预期的输出,正确输出应该如下:

=====new map=====
map[0]=0
map[1]=1
map[2]=2
map[3]=3

但是由输出可以知道,映射的值都相同且都是3。其实可以猜测映射的值都是同一个地址,遍历到切片的最后一个元素3时,将3写入了该地址,所以导致映射所有值都相同。

其实真实原因也是如此,因为for range创建了每个元素的副本,而不是直接返回每个元素的引用,如果使用该值变量的地址作为指向每个元素的指针,就会导致错误,在迭代时,返回的变量是一个迭代过程中根据切片依次赋值的新变量,所以值的地址总是相同的,导致结果不如预期。

修正后程序如下:

package main
import "fmt"
func main() {
  slice := []int{0, 1, 2, 3}
  myMap := make(map[int]*int)

  for index, value := range slice {
    num := value
    myMap[index] = &num
  }
  fmt.Println("=====new map=====")
  prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
  for key, value := range myMap {
    fmt.Printf("map[%v]=%v\n", key, *value)
  }
}

运行程序输出如下:

=====new map=====
map[2]=2
map[3]=3
map[0]=0
map[1]=1

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • golang中for循环遍历channel时需要注意的问题详解

    前言 for循环是Go语言唯一的循环结构,最近在做一个基于RabbitMQ的应用,由于官方的qos没有golang的版本,所以出了一点问题. 问题代码如下: _, ch, err := component.NewRabbitMQ() if err != nil { panic(err) } if err := ch.Qos(10, 0, true); err != nil { panic(err) } msgs, err := ch.Consume("push", "&quo

  • golang中range在slice和map遍历中的注意事项

    golang中range在slice和map遍历中的注意事项 package main import ( "fmt" ) func main() { slice := []int{0, 1, 2, 3} myMap := make(map[int]*int) for _,v :=range slice{ if v==1 { v=100 } } for k,v :=range slice{ fmt.Println("k:",k,"v:",v) }

  • go语言遍历文件夹示例

    用python遍历文件夹很方便,在go的世界里,我也需要这样的功能.找了找文档,里面有这个功能(具体参考这里:http://golang.org/pkg/path/filepath/ )-- 好,不废话了,我也想早点睡,直接上代码. 代码如下: 复制代码 代码如下: /* File      : getFilelist.go Author    : Mike E-Mail    : Mike_Zhang@live.com */ package main import (     "path/fi

  • Go语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    本文实例讲述了Go语言字典(map)用法.分享给大家供大家参考,具体如下: 字典是一种内置的数据结构,用来保存 键值对 的 无序集合. (1)字典的创建 1) make(map[KeyType]ValueType, initialCapacity) 2) make(map[KeyType]ValueType) 3) map[KeyType]ValueType{} 4) map[KeyType]ValueType{key1 : value1, key2 : value2, ... , keyN :

  • go for range遍历二维数组的示例

    go for range 遍历二维数组 var arry [2][3] int for index,_ := range arry { fmt.Print(index) } 运行结果: 0 1   没有遍历所有的6个元素. 二维数组 arry 可以理解为:拥有两个 一维数组元素 的一维数组,所以以上只是遍历了其的两个元素,index分别是0 1,value是两个 拥有三个int类型元素 的一维数组. var arry [2][3] int for index,value := range arr

  • GO语言实现列出目录和遍历目录的方法

    本文实例讲述了GO语言实现列出目录和遍历目录的方法.分享给大家供大家参考.具体如下: GO语言获取目录列表用 ioutil.ReadDir(),遍历目录用 filepath.Walk(),使用方法课参考本文示例. 具体示例代码如下: 复制代码 代码如下: package main import (  "fmt"  "io/ioutil"  "os"  "path/filepath"  "strings" )

  • Go语言for range(按照键值循环)遍历操作

    Go 语言可以使用 for range 遍历数组.切片.字符串.map 及通道(channel).通过 for range 遍历的返回值有一定的规律: 数组.切片.字符串返回索引和值. map 返回键和值. 通道(channel)只返回通道内的值. 遍历数组.切片--获得索引和元素 在遍历代码中,key 和 value 分别代表切片的下标及下标对应的值.下面的代码展示如何遍历切片,数组也是类似的遍历方法: for key, value := range []int{1, 2, 3, 4} { f

  • JS实现键值对遍历json数组功能示例

    本文实例讲述了JS实现键值对遍历json数组功能.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>www.jb51.net js键值对遍历json数组</title> </head> <body> <script type="text/javascript"

  • js实现hashtable的赋值、取值、遍历操作实例详解

    本文实例讲述了js实现hashtable的赋值.取值.遍历操作.分享给大家供大家参考,具体如下: 哈希表(Hashtable)这个概率应该是#c里面的概念,用来赋值.取值.遍历.排序操作提高效率.想起这个东西其实使我们以前经常遇到这样的面试题,一个很大的数组可能有100000个,如何快速知道它里面的出现最多的次数,那么这里我们可能就要用Hashtable的相关知识了.Javascript中,object的实现就是hash表,因此只要在object上封装点方法,再利用原生的hasOwnProper

  • python中dict字典的查询键值对 遍历 排序 创建 访问 更新 删除基础操作方法

    字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 : 字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的:但键不行,如果同一个键被赋值两次,后一个值会被记住. 值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组(列表这样的可变类型不能作为键). 一.字典的创建.访问: dict = {'Name': 'Zara', 'Age': 7,

  • vue中的循环遍历对象、数组和字符串

    目录 vue循环遍历对象.数组和字符串 1.循环遍历对象 2.循环遍历数组 3.循环遍历字符串 vue循环遍历,指令v-for 1.循环遍历 2.v-for遍历数组 3.v-for遍历对象 4.v-for使用中添加key vue循环遍历对象.数组和字符串 1.循环遍历对象 1.1vue 在html里面循环遍历对象 v-for=" (val, key , i) in dimItemMap" :key="key" val-每一项 key -key值 i-第几个 <

  • 详解Thymeleaf的三种循环遍历方式

    目录 循环遍历list集合 1.实体类 2.控制类 3.each.html 循环遍历map集合 1.控制类 2.each.html 循环遍历数组 循环遍历list集合 1.实体类 使用lombok插件,省去getter和setter,toString等方法的书写 代码 package com.springboot_thyleaf2.model; import lombok.Data; @Data public class User { private Integer id; private St

  • Go语言遍历map实现(访问map中的每一个键值对)

    map 的遍历过程使用 for range 循环完成,代码如下: scene := make(map[string]int) scene["route"] = 66 scene["brazil"] = 4 scene["china"] = 960 for k, v := range scene { fmt.Println(k, v) } 遍历对于Go语言的很多对象来说都是差不多的,直接使用 for range 语法即可,遍历时,可以同时获得键和值

  • JSON键值对序列化和反序列化解析

    什么是JSON? JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write and easy for machines to parse and generate. JSON is a text format that is completely language independent. 翻译:Json[javascrip

  • php数组函数序列之each() - 获取数组当前内部指针所指向元素的键名和键值,并将指针移到下一位

    each()定义和用法 each() 函数生成一个由数组当前内部指针所指向的元素的键名和键值组成的数组,并把内部指针向前移动. 返回的数组中包括的四个元素:键名为 0,1,key 和 value.单元 0 和 key 包含有数组单元的键名,1 和 value 包含有数据. 如果内部指针越过了数组范围,本函数将返回 FALSE. 语法 each(array)参数 描述 array 必需.规定要使用的数组. 例子 1 复制代码 代码如下: <?php $people = array("Pete

  • python字典键值对的添加和遍历方法

    添加键值对 首先定义一个空字典 >>> dic={} 直接对字典中不存在的key进行赋值来添加 >>> dic['name']='zhangsan' >>> dic {'name': 'zhangsan'} 如果key或value都是变量也可以用这种方法 >>> key='age' >>> value=30 >>> dic[key]=value >>> dic {'age': 30

随机推荐