经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
Golang: 数组和切片
来源:cnblogs  作者:JustDotNet  时间:2018/12/17 9:45:18  对本文有异议

数组

同其他语言一样,数组是一些相同类型的元素的集合。数组声明

数组的类型为 n[T],其中 n 表示数组中元素的个数,T 表示数组中元素的类型。数组元素的个数 n 也是数组类型的一部分

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 var a [5]int //int array a and length is 5
  7. 7 fmt.Println(a)
  8. 8 }
  1. var a [5]int 是我们常用的一种声明数组的方式。同时也会给数组种的所有元素赋值int的初始值0.运行代码我们得到:[0 0 0 0 0]

    我们还可以用shorhand 速记声明的方式声明和赋值数组:
  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := [5]int{1, 3, 4, 5, 6} //int array a and length is 5
  7. 7 fmt.Println(a)
  8. 8 }

这个代码的运行结果是:[1 3 4 5 6]

如果没有给所有的元素赋值,那么后面的元素会被赋予默认值。

 

在声明数组的时候,可以使用...来代替数组长度,编译器会帮我们计算数组长度

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := [...]int{1, 3, 6} //int array a and length is 3
  7. 7 fmt.Println(len(a))
  8. 8 }

这个代码的运行结果是3,表明编译器帮我们计算好了数组长度。

由于数组的长度属于数组类型的一部分,那么[3]int和[5]int 不是相同一类型,不可以相互赋值。

 

数组遍历

Go提供了for rang来让我们遍历数组,这样比用for 循环简洁一些。

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := [...]string{"a", "b"}
  7. 7
  8. 8 for i, v := range a { //range returns both the index and value
  9. 9 fmt.Printf(" the element %d of a is %s \n", i, v)
  10. 10 }
  11. 11 }

上面的代码运行结果是:

the element 0 of a is a
the element 1 of a is b 

切片

由于数组长度不可变,导致数组的应用场景大幅减少。还好Go给我们提供了切片。

把上面的代码稍微修改一下,我们来创建一个切片

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := [...]string{"a", "b", "c", "d", "e"}
  7. 7
  8. 8 for i, v := range a { //range returns both the index and value
  9. 9 fmt.Printf(" the element %d of a is %s \n", i, v)
  10. 10 }
  11. 11
  12. 12 b := a[2:3]
  13. 13 fmt.Println(b)
  14. 14 }

运行结果是

  1. the element 0 of a is a
  2. the element 1 of a is b
  3. the element 2 of a is c
  4. the element 3 of a is d
  5. the element 4 of a is e
  6. [c]

我们通过 a[start:end] 这样的语法创建了一个从 a[start] 到 a[end -1] 的切片。在上面代码中,我们用这种方式创建了长度为1 的切片b。

 

我们还可以使用和创建数组相似的方式来创建切片

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 b := []string{"a", "b", "c", "d", "e"}
  7. 7 fmt.Println(b)
  8. 8 }

需要注意的是[]中间是没有长度或者...的。这段代码创建了一个切片b,然后代码的运行结果是:[a b c d e]

切片的长度和容量

切片的长度就是切片中元素的个数。切片的容量是 切片创建的数组的长度减去创建切片时的start值。

具体我们看代码

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := [...]string{"a", "b", "c", "d", "e"}
  7. 7 b := a[1:2]
  8. 8 fmt.Printf("length of slice %d capacity %d", len(b), cap(b)) //length is 1 and capacity is 4
  9. 9
  10. 10 }

运行结果是:length of slice 1 capacity 4

append 追加数据到切片上

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := [...]string{"a", "b", "c", "d", "e"}
  7. 7 b := a[1:2]
  8. 8 fmt.Printf("length of slice %d capacity %d\n", len(b), cap(b)) //length is 1 and capacity is 4
  9. 9 b = append(b, "x", "y", "z", "m", "n")
  10. 10 fmt.Printf("length of slice %d capacity %d\n", len(b), cap(b)) //length is 1 and capacity is 8
  11. 11
  12. 12 }

第8行代码给切片b追加了5个元素,那么长度就是6,长度超过了容量4,go是怎么做的?如果容量超了,go会创建一个新的数组,容量翻倍,然后返回新数组的完整切片。

代码的运行结果是

  1. length of slice 1 capacity 4
  2. length of slice 6 capacity 8

 

我们还可以使用append把一个切片完整的追加到一个切片上:

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := []string{"a", "b"}
  7. 7 b := []string{"c", "d", "e"}
  8. 8 a = append(a, b...)
  9. 9 fmt.Println(a)
  10. 10 }

运行结果是:

  1. [a b c d e]

这里有点类似ES6的写法

  1. var arr = [1, 2, 3];
  2.  
  3. var arr1 = [...arr, 4, 5, 6];

切片是数组的一种外层表示,所以我们每次修改切片,最终都会将修改落到数组上。

但是这时候再修改切边,修改就不会再反应到原来的数组上。

make创建切片

我们还可以使用函数make来创建切片。func make([]T, len, cap) []T,其中cap参数是可选的。

  1. 1 package main
  2. 2
  3. 3 import "fmt"
  4. 4
  5. 5 func main() {
  6. 6 a := make([]int, 3)
  7. 7 fmt.Println(a)
  8. 8
  9. 9 }

 

切片和数组作为参数传递

 

先上两段代码,第一段:

  1. package main
  2. import "fmt"
  3. func main() {
  4. a := []string{"a", "b", "c", "d", "e"}
  5. fmt.Println("before call function:", a)
  6. changeZeroElementA(a)
  7. fmt.Println("after call function:", a)
  8. b := [5]string{"a", "b", "c", "d", "e"}
  9. fmt.Println("before call function:", b)
  10. changeZeroElementB(b)
  11. fmt.Println("after call function:", b)
  12. }
  13. func changeZeroElementA(arr []string) {
  14. //arr = []string{"X", "Y"}
  15. arr[0] = "changed"
  16. }
  17. func changeZeroElementB(arr [5]string) {
  18. arr[0] = "changed"
  19. }

结果是:

  1. before call function: [a b c d e]
  2. after call function: [changed b c d e]
  3. before call function: [a b c d e]
  4. after call function: [a b c d e]

第二段:

  1. package main
  2. import "fmt"
  3. func main() {
  4. a := []string{"a", "b", "c", "d", "e"}
  5. fmt.Println("before call function:", a)
  6. changeZeroElementA(a)
  7. fmt.Println("after call function:", a)
  8. b := [5]string{"a", "b", "c", "d", "e"}
  9. fmt.Println("before call function:", b)
  10. changeZeroElementB(b)
  11. fmt.Println("after call function:", b)
  12. }
  13. func changeZeroElementA(arr []string) {
  14. arr = []string{"X", "Y"}
  15. arr[0] = "changed"
  16. }
  17. func changeZeroElementB(arr [5]string) {
  18. arr[0] = "changed"
  19. }

运行结果:

  1. 1 before call function: [a b c d e]
  2. 2 after call function: [a b c d e]
  3. 3 before call function: [a b c d e]
  4. 4 after call function: [a b c d e]

看到这里是不是有些奇怪,其实go里面一切都是值传递。这里有全方面的解释:https://stackoverflow.com/questions/39993688/are-golang-slices-pass-by-value

切片是数组的一种外层表示,所以我们每次修改切片,最终都会将修改落到数组上。

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号