Go语言中操作切片
Go语言中切片不同于数组,数组长度不可变。但是切片的长度是不固定的,可以追加元素。切片是对数组一个连续片段的引用,所以切片是引用类型,因此在传递切片变量时将传递同一个指针,修改切片会影响其他使用该切片的对象。切片在运行时内部表示为$GOROOT\src\runtime\slice.go):
type slice struct { array unsafe.Pointer len int cap int }
arrary:指向底层数组某元素的指针,该元素也是切片的起始元素
len:切片长度
cap:切片最大容量,cap >= len
在运行时中,每个切片都是runtime.slice结构体类型的一个实例。切片长度可以通过内置函数len()获得,切片容量可以通过内置函数cap()获得。可以通过以下方法创建切片:
make(T, length, capacity) make(T, length) []T{element1, element2, ...} []T{}
1.切片的迭代操作
可以用关键字for ... range迭代切片。迭代时会返回两个值,一个是切片元素的索引,一个是切片元素的值的副本。
func main() { var s = []int{1, 2, 3} for _, element := range s { // _ 空标识符,丢弃索引值 fmt.Printf("element = %d, element_address = %X\n", element, &element) } } // element = 1, element_address = C0000180C8 // element = 2, element_address = C0000180C8 // element = 3, element_address = C0000180C8 // 运行结果可以看出,元素地址是相同的,它是迭代变量element的地址
迭代切片时要想获取到每个元素的地址,需要使用切片变量和索引:
func main() { var s = []int{1, 2, 3} for index, element := range s { fmt.Printf("element = %d, element_address = %X\n", element, &s[index]) } } // element = 1, element_address = C00001A0F0 // element = 2, element_address = C00001A0F8 // element = 3, element_address = C00001A100 // 从运行结果也可以看出:切片占用了“一段”连续的内存
2.切片删除/追加元素操作
Go语言没有提供用于删除数组和切片的语法,而是利用切片本身的特性来删除或者追加元素。
func main() { var s = []int{1, 2, 3} var s1 = []int{7, 8, 9} // 追加元素 // [1 2 3 4] s2 := append(s, 4) // [1 2 3 7 8 9] s3 := append(s, s1...) // 删除元素 // [1, 3] s4 := append(s[0:1], s[2:]...) }
3.查找某个元素是否存在于切片中
查找切片中是否存在某个元素需要根据相应的类型逐个对比。
func main() { s := []string{"slice", "features", "study", "in", "Go"} target1 := "study" target2 := "In" fmt.Println(isExist(s, target1)) // true fmt.Println(isExist(s, target2)) // false } func isExist(s []string, target string) bool { for _, i := range s { if i == target { return true } } return false }
4.查找切片中某元素的索引
通过内置包reflect的VauleOf函数获取切片的值,再通过for循环遍历数组并于给定元素进行比较,如果相等则返回索引。
import ( "fmt" "reflect" ) func main() { s1 := []string{"slice", "features", "study", "in", "Go"} s2 := []int{1, 3, 4, 9, 6, 7} fmt.Println(findIndex(s1, "Go")) // 4 fmt.Println(findIndex(s2, 4)) // 2 } func findIndex(slice, item interface{}) int { s := reflect.ValueOf(slice) for i := 0; i < s.Len(); i++ { index := s.Index(i) if index.Interface() == item { return i } } return -1 }
5.查找数组中最大值/最小值
使用for循环对切片进行遍历,找出最大/小值及其索引。
func main() { s := []int{121, 4, 354, 22, -44, 324, -245, 133, 101} maxValue := s[0] maxValueIndex := 0 for i := 0; i < len(s); i++ { if maxValue < s[i] { maxValue = s[i] maxValueIndex = i } } fmt.Println(maxValue) // 354 fmt.Println(maxValueIndex) // 2 }
6.删除有序数组重复值
对比切片中相邻两个元素AB的值是否相同,如果相同,直到找到元素值不相同的下一个元素C并将C赋值给B。
func main() { s := []int{1, 1, 5, 5, 7, 9} // [1 5 7 9] fmt.Println(removeDuplicates(s)) } func removeDuplicates(s []int) []int { if len(s) == 0 { return nil } l, r := 0, 1 for ; r < len(s); r++ { if s[l] == s[r] { continue } l++ s[l] = s[r] } return s[:l+1] }