slice 指向数组的窗口

  • 假设 planets 是一个数组,那么 planets[0:4] 就是一个切片,它切分出了数组里前 4 个元素。
  • 切分数组不会导致数组被修改,它只是创建了指向数组的一个窗口或视图,这种视图就是 slice 类型。

slice(切片) - 图1

切分数组

  • Slice 使用的是半开区间
    例如 planets[0:4],包含索引 0、1、2、3 对应的元素,不包括索引 4 对应的元素。
  1. package main
  2. import "fmt"
  3. func main() {
  4. planets := [...]string{
  5. "Mercury",
  6. "Venus",
  7. "Earth",
  8. "Mars",
  9. "Jupiter",
  10. "Saturn",
  11. "Uranus",
  12. "Neptune",
  13. }
  14. terrestrial := planets[0:4]
  15. gasGiants := planets[4:6]
  16. iceGiants := planets[6:8]
  17. fmt.Println(terrestrial, gasGiants, iceGiants)
  18. fmt.Println(gasGiants[0])
  19. giants := planets[4:8]
  20. gas := giants[0:2]
  21. ice := giants[2:4]
  22. fmt.Println(giants, gas, ice)
  23. iceGiantsMarkII := iceGiants
  24. iceGiants[1] = "Poseidon"
  25. fmt.Println(planets)
  26. fmt.Println(iceGiants, iceGiantsMarkII, ice)
  27. }

slice 的默认索引

  • 忽略掉 slice 的起始索引,表示从数组的起始位置进行切分;
  • 忽略掉 slice 的结束索引,相当于使用数组的长度作为结束索引。
  • 注意:slice 的索引不能是负数。
  • 如果同时省略掉起始和结束索引,那就是包含数组所有元素的一个 slice。
  • 切分数组的语法也可以用于切分字符串
    • 切分字符串时,索引代表的是字节数而非 rune 的数。
  1. package main
  2. import "fmt"
  3. func main() {
  4. planets := [...]string{
  5. "Mercury",
  6. "Venus",
  7. "Earth",
  8. "Mars",
  9. "Jupiter",
  10. "Saturn",
  11. "Uranus",
  12. "Neptune",
  13. }
  14. terrestrial := planets[:4]
  15. gasGiants := planets[4:6]
  16. iceGiants := planets[6:]
  17. fmt.Println(terrestrial, gasGiants, iceGiants)
  18. allPlanets := planets[:]
  19. fmt.Println(allPlanets)
  20. colonized := terrestrial[2:]
  21. fmt.Println(colonized)
  22. }

slice 的复合字面值

  • Go 里面很多函数都倾向于使用 slice 而不是数组作为参数。
  • 想要获得与底层数组相同元素的 slice,那么可以使用 [:] 进行切分
  • 切分数组并不是创建 slice 唯一的方法,可以直接声明 slice:
    • 例如 []string
  1. package main
  2. import "fmt"
  3. func main() {
  4. dwarfArray := [...]string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
  5. dwarfSlice := dwarfArray[:]
  6. dwarfs := []string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
  7. fmt.Println(dwarfSlice, dwarfs)
  8. fmt.Printf("array %T\n", dwarfArray)
  9. fmt.Printf("slice %T\n", dwarfs)
  10. }

切片的威力

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // hyperspace removes the space surrounding worlds
  7. func hyperspace(worlds []string) {
  8. for i := range worlds {
  9. worlds[i] = strings.TrimSpace(worlds[i])
  10. }
  11. }
  12. func main() {
  13. planets := []string{" Venus ", "Earth ", " Mars"}
  14. hyperspace(planets)
  15. fmt.Println(strings.Join(planets, ""))
  16. }

带有方法的切片

  • 在 Go 里,可以将 slice 或数组作为底层类型,然后绑定其它方法。
  1. package main
  2. import (
  3. "fmt"
  4. "sort"
  5. )
  6. func main() {
  7. planets := []string{
  8. "Mercury", "Venus", "Earth", "Mars",
  9. "Jupiter", "Saturn", "Uranus", "Neptune",
  10. }
  11. sort.StringSlice(planets).Sort()
  12. fmt.Println(planets)
  13. }

作业题

  • 编写一个程序:
    • 它通过给字符串 slice 中所有的行星加上“New ”前缀来完成行星的地球化处理,然后使用该程序对 Mars、Uranus、Neptune 实行地球化
    • 必须使用 planets 类型,并为之实现相应的 terraform 方法。
  1. package main
  2. import "fmt"
  3. // Planets attaches methods to []string.
  4. type Planets []string
  5. func (planets Planets) terraform() {
  6. for i := range planets {
  7. planets[i] = "New " + planets[i]
  8. }
  9. }
  10. func main() {
  11. planets := []string{
  12. "Mercury", "Venus", "Earth", "Mars",
  13. "Jupiter", "Saturn", "Uranus", "Neptune",
  14. }
  15. Planets(planets[3:4]).terraform()
  16. Planets(planets[6:]).terraform()
  17. fmt.Println(planets)
  18. }