前言
在golang中提供了for range
语法糖帮助我们方便的遍历数据或切片,也可以遍历map和channel;在rust中则提供了 for in
语法糖帮助我们方便的遍历Array,Vector或切片,也可以遍历map。本文将会通过多种类型的例子介绍两种语言中这些语法糖背后的机制以及使用不当可能遇到的陷阱。
遍历方式对比
Golang
我们先来看Golang中的三种遍历方式:
arr := []int{
2, 4, 6}
// 只要索引
for i := range arr {
fmt.Println(i)
}
// 索引和数值
for i, v := range arr {
fmt.Println(i, v)
}
// 只要数值
for _, v := range arr {
fmt.Println(v)
}
输出
0
1
2
0 2
1 4
2 6
2
4
6
Rust
首先我们要了解在rust中遍历arr有下面四种不同的方法,本质都是将当前arr转为了相应的iterator。
let arr = vec![1, 2, 3];
for a in arr {
println!("{}", a);
}
let arr = vec![1, 2, 3];
for a in arr.into_iter() {
println!("{}", a);
}
let arr = vec![1, 2, 3];
for a in arr.iter() {
println!("{}", a);
}
let mut arr = vec![1, 2, 3];
for a in arr.iter_mut() {
println!("{}", a);
}
其中 for a in arr
等价于for a in arr.into_iter()
,这种遍历方式会把当前arr中的变量 move 掉,执行遍历后,arr无法再使用。
for a in arr.iter()
返回arr中每一项的不可变借用,for a in arr.iter_mut()
返回arr中每一项的可变借用,遍历后arr可以继续使用。
如果还需要索引,那么就要使用iterator的enumerate方法,这个方法将当前迭代器封装成迭代元素是包含索引和元素的元组的迭代器,如下:
let arr = vec![1, 2, 3];
for (i, v) in arr.into_iter().enumerate() {
println!("{} {}", i, v);
}
let arr = vec![1, 2, 3];
for (i, v) in arr.iter().enumerate() {
println!("{} {}", i, v);
}
let mut arr = vec![1, 2, 3];
for (i, v) in arr.iter_mut().enumerate() {
println!("{} {}", i, v);
}
在Rust中还有一个常用的只返回索引的遍历方法:
for i in 1..4{
println!("{}",i);
}
输出:
1
2
3
可以看到 beg..end
是一个左闭右开的区间,不包含end。
并发任务分发
在实际项目开发中,经常会需要将一组任务数据分发给不同的goroutine或thread来并发执行。
Golang
我们先来看在Golang中常见的错误写法
func slice_trap_wrong() {
in := []int{
1, 2, 3}
for _, b := range in {
go func() {
fmt.Println("job", b)
}()
}
}
func main() {
slice_trap_wrong()
select {