slice 指向数组的窗口
- 假设 planets 是一个数组,那么 planets[0:4] 就是一个切片,它切分出了数组里前 4 个元素。
- 切分数组不会导致数组被修改,它只是创建了指向数组的一个窗口或视图,这种视图就是 slice 类型。
切分数组
- Slice 使用的是半开区间
例如 planets[0:4],包含索引 0、1、2、3 对应的元素,不包括索引 4 对应的元素。
package main
import "fmt"
func main() {
planets := [...]string{
"Mercury",
"Venus",
"Earth",
"Mars",
"Jupiter",
"Saturn",
"Uranus",
"Neptune",
}
terrestrial := planets[0:4]
gasGiants := planets[4:6]
iceGiants := planets[6:8]
fmt.Println(terrestrial, gasGiants, iceGiants)
fmt.Println(gasGiants[0])
giants := planets[4:8]
gas := giants[0:2]
ice := giants[2:4]
fmt.Println(giants, gas, ice)
iceGiantsMarkII := iceGiants
iceGiants[1] = "Poseidon"
fmt.Println(planets)
fmt.Println(iceGiants, iceGiantsMarkII, ice)
}
slice 的默认索引
- 忽略掉 slice 的起始索引,表示从数组的起始位置进行切分;
- 忽略掉 slice 的结束索引,相当于使用数组的长度作为结束索引。
- 注意:slice 的索引不能是负数。
- 如果同时省略掉起始和结束索引,那就是包含数组所有元素的一个 slice。
- 切分数组的语法也可以用于切分字符串
- 切分字符串时,索引代表的是字节数而非 rune 的数。
package main
import "fmt"
func main() {
planets := [...]string{
"Mercury",
"Venus",
"Earth",
"Mars",
"Jupiter",
"Saturn",
"Uranus",
"Neptune",
}
terrestrial := planets[:4]
gasGiants := planets[4:6]
iceGiants := planets[6:]
fmt.Println(terrestrial, gasGiants, iceGiants)
allPlanets := planets[:]
fmt.Println(allPlanets)
colonized := terrestrial[2:]
fmt.Println(colonized)
}
slice 的复合字面值
- Go 里面很多函数都倾向于使用 slice 而不是数组作为参数。
- 想要获得与底层数组相同元素的 slice,那么可以使用 [:] 进行切分
- 切分数组并不是创建 slice 唯一的方法,可以直接声明 slice:
package main
import "fmt"
func main() {
dwarfArray := [...]string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
dwarfSlice := dwarfArray[:]
dwarfs := []string{"Ceres", "Pluto", "Haumea", "Makemake", "Eris"}
fmt.Println(dwarfSlice, dwarfs)
fmt.Printf("array %T\n", dwarfArray)
fmt.Printf("slice %T\n", dwarfs)
}
切片的威力
package main
import (
"fmt"
"strings"
)
// hyperspace removes the space surrounding worlds
func hyperspace(worlds []string) {
for i := range worlds {
worlds[i] = strings.TrimSpace(worlds[i])
}
}
func main() {
planets := []string{" Venus ", "Earth ", " Mars"}
hyperspace(planets)
fmt.Println(strings.Join(planets, ""))
}
带有方法的切片
- 在 Go 里,可以将 slice 或数组作为底层类型,然后绑定其它方法。
package main
import (
"fmt"
"sort"
)
func main() {
planets := []string{
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune",
}
sort.StringSlice(planets).Sort()
fmt.Println(planets)
}
作业题
- 编写一个程序:
- 它通过给字符串 slice 中所有的行星加上“New ”前缀来完成行星的地球化处理,然后使用该程序对 Mars、Uranus、Neptune 实行地球化
- 必须使用 planets 类型,并为之实现相应的 terraform 方法。
package main
import "fmt"
// Planets attaches methods to []string.
type Planets []string
func (planets Planets) terraform() {
for i := range planets {
planets[i] = "New " + planets[i]
}
}
func main() {
planets := []string{
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune",
}
Planets(planets[3:4]).terraform()
Planets(planets[6:]).terraform()
fmt.Println(planets)
}