golang遍历时修改被遍历对象的示例详解

前言

很多时候需要将遍历对象中去掉某些元素,或者往遍历对象中添加元素,这时候就需要小心操作了。
对于go语言中的一些注意事项我做了总结和示例,留下点笔记。

遍历切片

1.遍历切片时去掉元素,错误示例:

func main() {
  arr := []int{1, 2, 3, 4}
  for i := range arr {
    if arr[i] == 3 {
      arr = append(arr[:i], arr[i+1:]...)
    }
  }
  fmt.Println(arr)
}

最终报错panic: runtime error: index out of range [3] with length 3,因为range在迭代时已经确定i的范围为[0,len(arr))的左闭右开的区间。
但是当满足arr[i] == 3时对arr进行了修改,缩短了arr的长度,此时len(arr)=3,最大下标为2,因此当执行arr[3]时会报错。

2.遍历切片时去掉元素,不会报错,但不建议的写法:

func main() {
  arr := []int{1, 2, 3, 4}
  for i, v := range arr {
    fmt.Println(i, v)
    if v == 3 {
      arr = append(arr[:i], arr[i+1:]...)
      // arr = []int{4, 5, 6, 7} // 可以将上一行代码替换,看最终遍历的i,v情况
    }
  }
  fmt.Println(arr)
}

还是回到range的用法,当执行for循环时就已经确定(i,v)的遍历元素值,及时循环过程中修改arr,也不会改变for要遍历的(i,v)值。
可以将上面代码修改一下,看下在循环中改变arr值时,后面遍历的(i,v)是不会随着arr的改变而改变的。

3.遍历切片时去掉元素,建议写法:

func main() {
  arr := []int{1, 2, 3, 4}
  for i := 0; i < len(arr); i++ {
    fmt.Println(i, arr[i])
    if arr[i] == 3 {
      arr = append(arr[:i], arr[i+1:]...)
      i--
    }
  }
  fmt.Println(arr)
}

该方案只修改i的值,在删除元素时进行i--,可以确保遍历arr没有问题,而且每次通过arr[i]获取切片值不存在问题。
当然用该方式也可以在遍历时添加元素,只要i也对应变化就没问题。

遍历map

1.遍历map时去掉元素,可参考官方示例,可看下官方描述,下面这种方案是安全的。

for key := range m {
  if key.expired() {
    delete(m, key)
  }
}

2.清空map所有元素,如下第一种是省事的写法,第二种不会产生新的对象,用哪种看个人喜好吧。

m = make(map[int]int) // 可以产生一个新对象,旧对象等着被垃圾回收

for k := range m {
  delete(m,k) // 循环遍历并删除map所有元素,好处是map缓存还在,下次添加时可直接使用缓存
}

总结

关于切片遍历时进行操作需要注意一些坑。
关于map遍历时进行操作相对坑少点,不过遍历map需要修改元素时,map的value要为指针类型,这点得谨记。

到此这篇关于golang遍历时修改被遍历对象的文章就介绍到这了,更多相关golang遍历对象内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang 实现json类型不确定时的转换

    将json转为结构体时,经常会遇到无法确定某个字段类型的情况.在Go中可以使用interface 任意类型来解决. // convert json to struct // type uncertain package main import ( "fmt" "encoding/json" ) type Host struct { Id interface{} IdcId interface{} } func main() { b := []byte(`{"

  • Golang空结构体struct{}用途,你知道吗

    golang 空结构体 struct{} 可以用来节省内存 a := struct{}{} println(unsafe.Sizeof(a)) // Output: 0 理由如下: 如果使用的是map,而且map又很长,通常会节省不少资源 空struct{}也在向别人表明,这里并不需要一个值 本例说明在map里节省资源的用途: set := make(map[string]struct{}) for _, value := range []string{"apple", "o

  • golang类型转换组件Cast的使用详解

    开源地址 https://github.com/spf13/cast Cast是什么? Cast是一个库,以一致和简单的方式在不同的go类型之间转换. Cast提供了简单的函数,可以轻松地将数字转换为字符串,将接口转换为bool类型等等.当一个明显的转换是可能的时,Cast会智能地执行这一操作.它不会试图猜测你的意思,例如,你只能将一个字符串转换为int的字符串表示形式,例如"8".Cast是为Hugo开发的,Hugo是一个使用YAML.TOML或JSON作为元数据的网站引擎. 为什么

  • golang 字符串比较是否相等的方法示例

    golang字符串比较的三种常见方法 fmt.Println("go"=="go") fmt.Println("GO"=="go") fmt.Println(strings.Compare("GO","go")) fmt.Println(strings.Compare("go","go")) fmt.Println(strings.EqualFol

  • Golang 1.16 中 Modules的主要变化更新

    01介绍 Golang 1.16 已经正式发布了,其中 Modules 有一些变化: 默认开启 Modules. 不自动修改 go.mod 和 go.sum. 通过指定 @version 后缀安装特定版本可执行文件. 新增 retract 指令撤回 Module 版本. 使用新增配置变量 GOVCS 指定特定模块使用特定版本控制工具. golang 1.16 默认开启 Modules,即使不存在go.mod,Go 命令现在默认情况下也会在module-aware(模块感知)模式下构建包. 在 g

  • golang修改结构体中的切片值方法

    golang修改结构体中的切片值,直接传结构体地址就可以 package main import "fmt" type rspInfo struct { KeyWords string `json:"key_words"` Value []string `json:"value"` } func setSlice(te *[]string){ str := "12" *te = append(*te,str) } //结构提传

  • golang 切片截取参数方法详解

    以 s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}为例 0. 建议:做slice截取时建议用两个参数,尤其是从底层数组进行切片操作时,因为这样在进行第一次append操作时,会给切片重新分配空间,这样减少切片对数组的影响. 1. 结论:s = s[low : high : max] 切片的三个参数的切片截取的意义为 low为截取的起始下标(含), high为窃取的结束下标(不含high),max为切片保留的原切片的最大下标(不含max):即新切片从老切片的low

  • golang的强制类型转换实现

    golang是一种强类型语言,虽然在代码中经常看到这种写法,i:=10这其实这是编译器自动做了类型推断在编译期间.编译器会对数据进行类型检查.不同类型的数据不能赋值,不能在函数中传参.强类型语言有一些优势,很多的错误会在编译期间被检查出来,不想php和python等弱类型语言,很多错误只有运行到才能被发现.同样,强类型也有一些缺点,写代码的时候要考虑数据类型了,失去了一些灵活性. 言归正传,开始golang的类型转换问题 golang的类型转换和C/C++ java等语言的类型转换还有点区别 C

  • golang遍历时修改被遍历对象的示例详解

    前言 很多时候需要将遍历对象中去掉某些元素,或者往遍历对象中添加元素,这时候就需要小心操作了. 对于go语言中的一些注意事项我做了总结和示例,留下点笔记. 遍历切片 1.遍历切片时去掉元素,错误示例: func main() { arr := []int{1, 2, 3, 4} for i := range arr { if arr[i] == 3 { arr = append(arr[:i], arr[i+1:]...) } } fmt.Println(arr) } 最终报错panic: ru

  • 使用java8 API遍历过滤文件目录及子目录和隐藏文件示例详解

    1. 使用Files.list()迭代目录及其子目录文件 Files.list()可以迭代目录及其子目录文件 Files.list(Paths.get(".")) //当前目录 .forEach(System.out::println); 输出: .\filename1.txt .\directory1 .\filename2.txt .\Employee.java 2. 使用 filter表达式过滤文件 过滤器函数引用,isRegularFile表示普通文件 Files.list(P

  • JavaIO字符操作和对象操作示例详解

    目录 字符操作 编码与解码 String 的编码方式 Reader 与 Writer 实现逐行输出文本文件的内容 对象操作 序列化 Serializable transient 字符操作 编码与解码 编码就是把字符转换为字节,而解码是把字节重新组合成字符. 如果编码和解码过程使用不同的编码方式那么就出现了乱码. GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节: UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节: UTF-16be 编码中,中文字符和英文字符都占

  • golang中的三个点 '...'的用法示例详解

    '-' 其实是go的一种语法糖. 它的第一个用法主要是用于函数有多个不定参数的情况,可以接受多个不确定数量的参数. 第二个用法是slice可以被打散进行传递. 下面直接上例子: func test1(args ...string) { //可以接受任意个string参数 for _, v:= range args{ fmt.Println(v) } } func main(){ var strss= []string{ "qwr", "234", "yui

  • c#对象反序列化与对象序列化示例详解

    1.对象序列化的介绍 (1).NET支持对象序列化的几种方式二进制序列化:对象序列化之后是二进制形式的,通过BinaryFormatter类来实现的,这个类位于System.Runtime.Serialization.Formatters.Binary命名空间下.SOAP序列化:对象序列化之后的结果符合SOAP协议,也就是可以通过SOAP 协议传输,通过System.Runtime.Serialization.Formatters.Soap命名空间下的SoapFormatter类来实现的.XML

  • spring MVC中传递对象参数示例详解

    前言 初学java,由于项目紧急,来不及仔细的研究,在传递参数时就老老实实的一个一个的采用@RequestParam注解方式传递,最近认真看了一下,发现java也具有类似Asp.net Mvc传递对象做参数的方式,即采用@ModelAttribute注解的方式,接收方式如下: @RequestMapping("hello") public String Hello(@ModelAttribute("user") User user) { System.out.pri

  • Pandas之MultiIndex对象的示例详解

    约定 import pandas as pd from pandas import DataFrame import numpy as np MultiIndex MultiIndex表示多级索引,它是从Index继承过来的,其中多级标签用元组对象来表示. 一.创建MultiIndex对象 创建方式一:元组列表 m_index1=pd.Index([("A","x1"),("A","x2"),("B",&q

  • C++预定义的流对象基本示例详解

    目录 C++预定义的流对象 示例说明 总结: C++预定义的流对象 C++预定义的流对象是可用于输入和输出的数据流向对象.它们是在C++语言中内置的,可以使用标准库的iostream头文件来调用这些流对象. 在这篇文章中,我们将介绍C++预定义的流对象,并提供一些示例说明. 示例说明 cin: cin是标准输入流对象,用于从控制台读取输入. 示例: int num; cout << "Enter a number: "; cin >> num; cout <

  • Java实现广度优先遍历的示例详解

    目录 什么是广度优先 一个简单的例子 程序实现 总结 什么是广度优先 广度就是扩展开,广度优先的意思就是尽量扩展开.所以在算法实现的时候,就是一个循环遍历枚举每一个邻接点.其基本思路就是按层扩展,扩得越广越好. 伪代码如下: for(int i = 0; i < children.size(); i++){ children.get(i); // 调用每一个子节点 } 一个简单的例子 我们以一个简单的迷宫为例,以1代表墙,0代表路径,我们构造一个具有出入口的迷宫. 1 1 0 1 1 1 1 1

  • JS递归遍历查询是否有权限示例详解

    目录 前言 需求分析 设计思路 代码 声明查找模板如下 js 版本 ts 版本 后记 前言 最近参与了一个基于 qiankun 构建的微前端大型项目,涉及到十几个子应用,基于基座独立开发了一个完善的权限中心模块.而权限中心中涉及到了 模块 > 一级菜单 > N级菜单/按钮 结构的权限管理. 这次的需求是在其中一个子应用的按钮级别的权限管理,在鉴权阶段写了一个小的方法,用来从权限树中查询是否有某一个按钮的权限,从而控制用户对于按钮的使用权限. 需求分析 权限的每一层对应的子菜单的键不尽相同. 在

随机推荐