数据类型之切⽚
章节
1. 切⽚的定义
2. 多维切⽚
3. 切⽚的长度和容量
4. 切⽚的操作
5. for-range对切⽚的迭代
6. append和copy函数
7. 多个切⽚共享底层数组
8. 切⽚排序
1、切⽚的定义
数组的局限是长度是固定的,不能更改、扩容。因此会⽤到另这⼀种类型,即切⽚(slice),也称作动态数组。
切⽚是由相同类型元素组成的有序集合,主要特性
切⽚是引⽤类型,其内部维护三个字段: len(长度)、cap(容量),还有⼀个指向数组的指针.
切⽚本⾝存储任何数据,⽽是切⽚内部的指针指向了⼀个底层数组,这个数组存放数据
切⽚的长度、容量可以改变的,当元素的长度⼤于容量时切⽚将会⾃动扩容,⼀旦扩容,底层会指向新的底层数组⼀般通过make创建并初始化切⽚、⽀持多维切⽚
切⽚的零值为nil,是不能直接使⽤的,需要初始化才能使⽤
如果多个slice共享相同底层数组,其中⼀个修改变会影响全部,因为切⽚是对数组的指向
使⽤len、cap函数分别获取切⽚的长度、容量
通过for语句遍历切⽚
appned与copy函数分别对切⽚进⾏元素添加、拷贝
切⽚的定义与初始化
// 声明⼀个未初始化的切⽚
var a []类型
// 通过make函数创建切⽚,容量可以省略,默认等于长度
make([]类型, 长度, 容量)
// 声明并初始化切⽚
[]类型{元素1, 元素2, 元素3...}
⽰例:
package main
import (
"fmt"
)
func main() {
// 1、声明⼀个叫s1的空切⽚,默认长度为0, 值为nil
var s1 []int
fmt.Println(len(s1)) // 输出: [] 0
// 未初始化的切⽚值为nil
if s1 == nil {
fmt.Println("ok") // 输出: ok
}
// 没有初始化的切⽚是不能操作的
s1[0] = 100// 编译错误
// 2、字⾯量声明并初始化⼀个切⽚,此时长度与容量相等
s3 := []string{"a", "b", "c", "d"}
fmt.Println(s3)          // 输出: [a b c d]
// 3、使⽤make函数创建⼀个切⽚
i1 := make([]int, 5)  // 指定长度
fmt.Println(i1)        // 输出: [0 0 0 0 0]
// 4、从数组创建⼀个slice切⽚,可以⽤于与数组转切⽚
array := [5]string{"A", "B", "C", "D", "E"}
var slice []string = array[1:3]  // 得到的是⼀个切⽚类型
  var s []string = arry[:]
fmt.Println(slice)                // 输出: [B C D]
}
如果切⽚的位置没有赋值,为元素类型的零值
package main
import (
"fmt"
)
func main() {
slice := make([]int, 5)
fmt.Println(slice) // 输出: [0 0 0 0 0]    # 这⾥索引位置没有赋值,为元素类型的零值
slice[0] = 100
slice[1] = 200
fmt.Println(slice) // 输出:[100 200 0 0 0]
}
建议⽤切⽚时指定长度
2、多维切⽚
也就是切⽚⾥⾯可以嵌套切⽚
package main
import (
"fmt"
)
func main() {
// 切⽚嵌套string类型的切⽚
slice := [][]string{
{"A", "B", "c"},
{"a", "b", "c"},
}
slice[0][1] // 输出:"A"
slice[1][0] // 输出:"a"
// 切⽚⾥嵌套int类型的切⽚
slice := [][4]int{
{1, 2, 3, 4},
{10, 20, 30, 40},
{100, 200, 300, 400},
}
/
/ 切⽚嵌套map类型的切⽚
slice_map := []map[int]string{
{1: "a", 2: "b", 3: "c"},
{10: "a", 20: "b", 30: "c"},
}
}
3、切⽚的长度和容量
长度是指切⽚的元素个数,容量是指切⽚最⼤⽀持元素数,默认情况下,长度等于容量,如果超过切⽚的容量,go会⾃动扩容.通过len和cap函数分别获取切⽚的长度与容量
package main
import (
"fmt"
)
func main() {
s := []string{"a", "b", "c", "d"}
fmt.Println(len(s), cap(s))            // 输出: 4    4
}
4、通过索引操作切⽚
按照[开始:结束]进⾏切⽚、不能负索引
package main
import (
  "fmt"
)
func main() {
  slice := []float64{11.11, 22.22, 33.33, 44.44, 55.55}
  fmt.Println(slice[1:3])  // 输出: [22.22 33.33] # 索引1到2
  fmt.Println(slice[2:4])  // 输出:[33.33 44.44] # 索引2到3
  fmt.Println(slice[:])  // 输出:[11.11 22.22 33.33 44.44 55.55] # 切⽚的副本
  fmt.Println(slice[2:])  // 输出: [33.33 44.44 55.55] # 索引2到最后⼀个
  fmt.Println(slice[:4])  // 输出: [11.11 22.22 33.33 44.44] # 索引0到3
  slice[0] = 100       // 设置索引0的值
  fmt.Println(slice[-1])  // 错误:不能负索引
}
5、遍历切⽚
package main
import (
"fmt"
)
func main() {
// ⽅法1:通过for-range
s2 := []string{"a", "b", "c", "d"}
for index, item := range s2 {
fmt.Printf("索引: %d, 值: %s\n", index, item)
}
  // ⽅法2
for i := 0; i < len(s2); i++ {
fmt.Printf("索引: %d, 值: %s\n", i, s2[i])
}
}
6、append和copy
切⽚的是可变的,所以可以改变它的与容量与长度
append函数⽤于将元素添加的切⽚的末尾,可以添加⼀个或多个元素,返回的是⼀个新的切⽚
如果对零值的切⽚进⾏append,那么这个切⽚就直接初始化可以使⽤了
如果对切⽚添加元素后超过了原先的容量, go会⾃动重新分配切⽚的容量,容量为原先的两倍
copy函数⽤于将⼀个切⽚的元素复制到另⼀个切⽚,得到是⼀个整数,表⽰复制了多少个元素到切⽚package main
import (
"fmt"
)
func main() {
slice := []int{1, 2, 3, 4}
// 添加⼀个元素
new_slice := append(slice, 100) // 添加100到切⽚的尾部,得到⼀个新的切⽚
fmt.Println(new_slice)          // 输出: [1 2 3 4 100]
fmt.Println(slice)              // 输出:[1 2 3 4]  # 原先的切⽚是不变的
// ⼀次性添加多个元素
two_slice := append(slice, 100, 200, 300)
fmt.Println(two_slice) // 输出: [1 2 3 4 100 200 300]
/
/ 如果对⼀个零值的切⽚进⾏append,那么直接可以使⽤(初始化)
var x []float64
x = append(x, 100.11, 100.22)
fmt.Println(x) // 输出: [100.11 100.22]
// 合并两个相同元素类型的切⽚
s1 := []int{1, 2, 3, 4}
s2 := []int{100, 200, 300, 400}
s3 := append(s1, s2...)  // 后⾯需要加...
fmt.Println(s3)          // 输出: [1 2 3 4 100 200 300 400]
}
如果切⽚添加元素后超过了原先的容量, go会⾃动重新分配切⽚的容量,容量为原先的两倍
package main
import (
"fmt"
)
func main() {
slice := make([]int, 5, 8)          // ⽣成⼀个切⽚,长度为5,容量为8
fmt.Println(len(slice), cap(slice)) // 输出: 5 8
// 为切⽚添加元素
new_slice := append(slice, 1, 2, 3, 4, 5)
fmt.Println(new_slice)                      // 输出: [0 0 0 0 0 1 2 3 4 5]
fmt.Println(len(new_slice), cap(new_slice))  // 输出: 10 16      # 可以看到超过了切⽚容量,扩容为原先的两倍
}
copy函数
⽤法: copy(dst, src) --> int
package main
import "fmt"
func main() {
s1 := []string{"a", "b", "c", "d", "e", "f"}
s2 := []string{"1", "2", "3"}
count := copy(s2, s1)
fmt.Println(count) // 输出3
fmt.Println(s2)    // 输出[a b c], s2被s1中的前三个元素覆盖了
}
7、多个切⽚共享底层数组
切⽚的底层是数组,如果底层的数组发⽣变化,会影响关联这个数组的切⽚
package main
import (
"fmt"
)
func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names) // [John Paul George Ringo]
a := names[0:2]  // [John Paul]    得到切⽚
b := names[1:3]  // [Paul George]  得到切⽚
fmt.Println(a, b) // [John Paul] [Paul George]
b[0] = "XXX"// 修改b
fmt.Println(a, b)  // [John Paul] [XXX George]  原先的数组也被影响
fmt.Println(names) // [John XXX George Ringo]    原先的数组也被影响
}
8、切⽚排序
切⽚排序可以使⽤sort包,sort.Ints对整数进⾏排序,sort.Strings对字符串进⾏排序,sort.Float64对浮点数进⾏排序,具体参考sort包使⽤package main
import (
"fmt"
"sort"
)
func main() {
s1 := []int{10, 1, 3, 20, 5, 6, 34, 23}
s2 := []string{"b", "c", "d", "e", "a"}
sort.Ints(s1)
sort.Strings(s2)
fmt.Println(s1) // [1 3 5 6 10 20 23 34]  数字按从⼩到⼤排序,原先的切⽚被修改了
字符串截取方法slicefmt.Println(s2) // [a b c d e]            字母从a-b排序,原先的切⽚被修改
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。