Go 语言范围(Range)
Posted 知其黑、受其白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go 语言范围(Range)相关的知识,希望对你有一定的参考价值。
阅读目录
Go 语言范围(Range)
Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。
在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。
for 循环的 range 格式可以对 slice、map、数组、字符串 等进行迭代循环。
格式如下:
for key, value := range oldMap
newMap[key] = value
以上代码中的 key 和 value 是可以省略。
如果只想读取 key,格式如下:
for key := range oldMap
或者这样:
for key, _ := range oldMap
如果只想读取 value,格式如下:
for _, value := range oldMap
range 关键字在 go 语言中是相当常用好用的语法糖,可以用在 for 循环中迭代 array、slice、map、channel、字符串所有涉及到遍历输出的东西。
切片迭代
nums := []int1, 2, 3
for k, v := range nums
fmt.Printf("key: %v , value: %v \\n", k, v)
key: 0 , value: 1
key: 1 , value: 2
key: 2 , value: 3
map迭代起始节点就随机了
kvs := map[string]string
"a": "a",
"b": "b",
for k, v := range kvs
fmt.Printf("key: %v , value: %v \\n", k, v)
PS E:\\go_test> go run .\\main.go
key: a , value: a
key: b , value: b
PS E:\\go_test>
字符串迭代
for k, v := range "hello"
//注意这里单个字符输出的是ASCII码,用 %c 代表输出字符
fmt.Printf("key: %v , value: %c\\n", k, v)
PS E:\\go_test> go run .\\main.go
key: 0 , value: h
key: 1 , value: e
key: 2 , value: l
key: 3 , value: l
key: 4 , value: o
PS E:\\go_test>
channel
ch := make(chan int, 10)
ch <- 11
ch <- 12
// 不用的时候记得关掉,不关掉又没有另一个goroutine存在会死锁哦,可以注释掉这一句体验死锁
close(ch)
for x := range ch
fmt.Println(x)
PS E:\\go_test> go run .\\main.go
11
12
PS E:\\go_test>
结构体
package main
import (
"fmt"
"reflect"
)
type Student struct
name string
age int
func main()
v := reflect.ValueOf(Student"乔峰", 29)
count := v.NumField()
for i := 0; i < count; i++
f := v.Field(i) //字段值
switch f.Kind()
case reflect.String:
fmt.Println(f.String())
case reflect.Int:
fmt.Println(f.Int())
PS E:\\go_test> go run .\\main.go
乔峰
29
PS E:\\go_test>
package main
import (
"fmt"
"reflect"
)
type LanType struct
s1, s2, s3 string
var language interface = LanType"php", "Go", "Python3"
func main()
value := reflect.ValueOf(language)
for i := 0; i < value.NumField(); i++
fmt.Printf("字段索引 %d: %v\\n", i, value.Field(i))
PS E:\\go_test> go run .\\main.go
字段索引 0: Php
字段索引 1: Go
字段索引 2: Python3
PS E:\\go_test>
golang中数组与切片的区别详析
- 声明方式不同,数组需要指定大小,而切片不用
- 数组是值传递,切片是引用传递
Go切片和Go数组定义
Go 切片
又称动态数组,它实际是基于数组类型做的一层封装。
Go 数组
数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从 0 开始的下标索引访问元素值。
在初始化后长度是固定的,无法修改其长度。
当作为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数 len(array)
获取其长度。
切片与数组的区别
- 数组的零值是元素类型的零值,切片的零值是nil;
- 数组是固定长度,切片是可变的长度。
- 数组是值类型,切片是引用类型。
1、 Go 中的数组是值类型,换句话说,如果你将一个数组赋值给另外一个数组,那么,实际上就是将整个数组拷贝一份。
因此,在 Go 中如果将数组作为函数的参数传递的话,那效率就肯定没有传递指针高了。
2、数组的长度也是类型的一部分,这就说明 [10]int
和 [20]int
不是同一种数据类型。
并且Go 语言中数组的长度是固定的,且不同长度的数组是不同类型,这样的限制带来不少局限性。
3、切片(slice)是一个拥有相同类型元素的可变长序列,可以方便地进行扩容和传递,实际使用时比数组更加灵活,这也正是切片存在的意义。
而且切片是引用类型,因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。
数组
var arr1 [4]int
fmt.Printf("arr1 val:%d arr1 len:%d arr1 cap:%d\\n",
arr1, len(arr1), cap(arr1))
arr1 val:[0 0 0 0]
arr1 len:4
arr1 cap:4
arr := [4]int
fmt.Printf("val:%d len:%d cap:%d\\n",
arr, len(arr), cap(arr))
// val:[0 0 0 0] len:4 cap:4
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
// arr[4] = 5
// 报错:invalid array index 4
(out of bounds for 4-element array)
fmt.Printf("val:%d len:%d cap:%d\\n",
arr, len(arr), cap(arr))
// val:[1 2 3 4] len:4 cap:4
ss := arr[:]
ssPtr := (*reflect.SliceHeader)(unsafe.Pointer(&ss)).Data
fmt.Printf("ss val:%d len:%d cap:%d ptr:%v\\n",
ss, len(ss), cap(ss), ssPtr)
/*
ss val:[1 2 3 4]
len:4
cap:4
ptr:824633803136
*/
ss2 := arr[:]
ss2Ptr := (*reflect.SliceHeader)(unsafe.Pointer(&ss2)).Data
fmt.Printf("ss2 val:%d len:%d cap:%d ptr:%v\\n",
ss2, len(ss2), cap(ss2), ss2Ptr)
/*
ss2 val:[1 2 3 4]
len:4
cap:4
ptr:824633803136
*/
切片
注意:切片的容量可以根据元素的个数的增多自动扩容,但是不会根据元素的个数的减少自动缩容。
var s []int
if s == nil
fmt.Println("nil")
fmt.Printf("s val:%d len:%d cap:%d\\n",
s, len(s), cap(s))
/*
s val:[]
len:0
cap:0
*/
s = append(s, 1)
fmt.Printf("s val:%d len:%d cap:%d\\n",
s, len(s), cap(s))
/*
s val:[1]
len:1
cap:1
*/
s = append(s, 1)
s = append(s, 2)
fmt.Printf("s val:%d len:%d cap:%d\\n",
s, len(s), cap(s))
/*
s val:[1 2]
len:2
cap:2
*/
s = append(s, 1)
s = append(s, 2)
s = append(s, 3)
fmt.Printf("s val:%d len:%d cap:%d\\n",
s, len(s), cap(s))
/*
s val:[1 2 3]
len:3
cap:4
*/
代码
package main
import "fmt"
func main()
fmt.Println("--------------------数组声明与赋值-----------------")
// 指定数组大小
var a1 [5]int
// 自动推断数组大小
a2 := [...]int1, 2, 3
fmt.Println("a1=", a1, "a2=", a2)
// 按索引赋值
a3 := [...]int2: 2, 4: 4
fmt.Println("a3=", a3)
// 按索引赋值
a4 := [6]int2: 2, 4: 4
fmt.Println("a4=", a4)
fmt.Println("-------------------- 切片声明与初始化-----------------")
// 定义切片
var b1 []int
fmt.Println("b1=", b1)
// 初始化
b2 := make([]int, 3, 5)
fmt.Printf("b2=%v,len=%d,cap=%d\\n", b2, len(b2), cap(b2))
fmt.Println("--------------------值传递与引用传递-----------------")
a := [4]float6467.7, 89.9, 21, 78
b := []int2, 3, 5
fmt.Printf("变量a---地址:%p,类型:%T,数值:%v,长度:%d \\n", &a, a, a, len(a))
fmt.Printf("变量b---地址:%p,类型:%T,数值:%v,长度:%d \\n", &b, b, b, len(b))
c := a
d := b
fmt.Printf("变量c---地址:%p,类型:%T,数值:%v,长度:%d \\n", &c, c, c, len(c))
fmt.Printf("变量d---地址:%p,类型:%T,数值:%v,长度:%d \\n", &d, d, d, len(d))
a[1] = 200
fmt.Println("a=", a, "c=", c)
d[0] = 200
fmt.Println("b=", b, "d=", d)
PS E:\\go_test> go run .\\main.go
--------------------数组声明与赋值-----------------
a1= [0 0 0 0 0] a2= [1 2 3]
a3= [0 0 2 0 4]
a4= [0 0 2 0 4 0]
-------------------- 切片声明与初始化-----------------
b1= []
b2=[0 0 0],len=3,cap=5
--------------------值传递与引用传递-----------------
变量a---地址:0xc0000141a0,类型:[4]float64,数值:[67.7 89.9 21 78],长度:4
变量b---地址:0xc000008090,类型:[]int,数值:[2 3 5],长度:3
变量c---地址:0xc000014200,类型:[4]float64,数值:[67.7 89.9 21 78],长度:4
变量d---地址:0xc0000080d8,类型:[]int,数值:[2 3 5],长度:3
a= [67.7 200 21 78] c= [67.7 89.9 21 78]
b= [200 3 5] d= [200 3 5]
PS E:\\go_test>
数组声明与赋值
// 指定数组大小
var a1 [5]int
// 自动推断数组大小
a2 := [...]int1, 2, 3
fmt.Println("a1=", a1, "a2=", a2)
// a1= [0 0 0 0 0] a2= [1 2 3]
// 按索引赋值
a3 := [...]int2: 2, 4: 4
fmt.Println("a3=", a3)
// a3= [0 0 2 0 4]
// 按索引赋值
a4 := [6]int2: 2, 4: 4
fmt.Println("a4=", a4)
// a4= [0 0 2 0 4 0]
切片声明与初始化
// 定义切片
var b1 []int
fmt.Println("b1=", b1)
// b1= []
// 初始化
b2 := make([]int, 3, 5)
fmt.Printf("b2=%v,len=%d,cap=%d\\n",
b2, len(b2), cap(b2))
// b2=[0 0 0],len=3,cap=5
值传递与引用传递
a := [4]float6467.7, 89.9, 21, 78
fmt.Printf("变量a---地址:%p,类型:%T,数值:%v,长度:%d \\n",
&a, a, a, len(a))
变量a---地址:0xc000014180,
类型:[4]float64,
数值:[67.7 89.9 21 78],
长度:4
b := []int2, 3, 5
fmt.Printf("变量b---地址:%p,类型:%T,数值:%v,长度:%d \\n",
&b, b, b, len(b))
变量b---地址:0xc000008078,
类型:[]int,
数值:[2 3 5],
长度:3
b := []int2, 3, 5
a := [4]float6467.7, 89.9, 21, 78
c := a
d := b
fmt.Printf("变量c---地址:%p,类型:%T,数值:%v,长度:%d \\n",
&c, c, c, len(c))
变量c---地址:0xc000014180,
类型:[4]float64,
数值:[67.7 89.9 21 78],
长度:4
b := []int2, 3, 5
a := [4]float6467.7, 89.9, 21, 78
// c := a
d := b
fmt.Printf("变量d---地址:%p,类型:%T,数值:%v,长度:%d \\n",
&d, d, d, len(d))
变量d---地址:0xc000008078,
类型:[]int,
数值:[2 3 5],
长度:3
a := [4]float6467.7, 89.9, 21, 78
c := a
b := []int2, 3, 5
d := b
a[1] = 200
fmt.Println("a=", a, "c=", c)
d[0] = 200
fmt.Println("b=", b, "d=", d)
a= [67.7 200 21 78] c= [67.7 89.9 21 78]
b= [200 3 5] d= [200 3 5]
以上是关于Go 语言范围(Range)的主要内容,如果未能解决你的问题,请参考以下文章