数组和切片4

切片的遍历:

切片的遍历和数组一样,也有两种方式

  1)for 循环常规方式遍历

  2)for-range 结构遍历切片


两种方式都在下面的代码里:

案例演示:

func main() {

  //使用常规的for循环遍历切片
  var arr [5]int = [...]int{10,20,30,40,50}
  slice := arr[1:4] // 20, 30, 40
  for i := 0; i < len(slice); i++ {
  fmt.Printf("slice[%v]=%v ", i, slice[i])
}

fmt.Println()
  //使用for--range 方式遍历切片
  for i, v := range slice {
    fmt.Printf("i=%v v=%v \n", i, v)
  }
}

 

切片的注意事项和细节说明:

切片初始化时 var slice = arr[startIndex:endIndex]
说明:从arr 数组下标为startIndex,取到下标为endIndex的元素,不含arr[endIndex]。

切片初始化时,仍然不能越界。范围在 [0-len(arr)] 之间,但是可以动态增长。

  1)var slice = arr[0:end] 可以简写 var slice = arr[:end]
  2)var slice = arr[start:len(arr)] 可以简写: var slice = arr[start:]
  3)var slice = arr[0:len(arr)] 可以简写: var slice = arr[:]


cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。

切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间供切片来使用

切片可以继续切片

 

用append内置函数,可对切片进行动态追加

func main() {

  //用append内置函数,可以对切片进行动态追加

  var slice3 = []int{100, 200, 300}

  //通过append直接给slice3追加具体的元素

  slice3 = append(slice3, 400, 500, 600)

  //通过append将切片slice3追加给slice3

  slice3 = append(slice3, slice3...)

  fmt.Println("slice3=", slice3)
}

切片append操作的底层原理分析:

  1)切片append操作的本质就是对数组扩容

  2)go底层会创建一个新的数组newArr(按照扩容后大小)

  3)将slice原来包含的元素拷贝到新的数组newArr

  4)slice重新引用到newArr

  5)注意newArr是在底层来维护的,程序员不可见

  6)案例演示说明:

 

 

切片的拷贝操作:

切片使用copy内置函数完成拷贝,举例说明:

func main() {

  var slice4 []int = []int {1,2,3,4,5}
  var slice5 = make([]int, 10)
  copy(slice5, slice4)
  fmt.Println("slice4=", slice4)
  fmt.Println("slice5=", slice5)
}


对上面代码的说明:

(1)copy(para1, para2):参数的数据类型都是切片类型。

(2)按照上面的代码来看,slice4和slice5的数据空间是独立的,相互不影响,也就是说 slice4[0]=999,slice5[0] 仍然是1。


思考题:下面的代码有没有错误:

var a []int = []int {1,2,3,4,5}
var slice = make([]int, 1)
fmt.Println(slice)   //0
copy(slice, a)   //这里是不会报长度不够这个错的,虽然长度只有1。长度有多大,就拷贝几个值过来
fmt.Println(slice)   //1

说明:上面的代码没有问题,可以运行,最后输出的结果是 【1】

 

 

 

 

 

 

 

 

 

 

 

string和slice:

1)string底层是一个byte数组,因此string也可以进行切片处理

案例演示:

func main() {

  str := "hello@atguigu"
  slice := str[6:]
  fmt.Println("slice=",slice)
}

2)string和切片在内存的形态,以“abcd” 画出内存示意图

 

3)string是不可变的,也就说不能通过 str[0] = 'z' 方式来修改字符串

4)如果需要修改字符串,可以先将string -> []byte / 或者 []rune -> 修改 -> 重写转成string

func main() {

  str := "hello@atguigu"
  slice := str[6:]
  fmt.Println("slice=",slice)

  //str[0] = 'z' [编译不会通过,报错,原因是string是不可变的]

  // arr1 := []byte(str)
  // arr1[0] = 'z'
  // str = string(arr1)
  // fmt.Println("str=", str)

  //细节,我们转成[]byte后,可以处理英文和数字,但是不能处理中文
  //原因是 []byte 按字节来处理的,而一个汉字是3个字节,因此就会出现乱码
  //解决方法是将 string 转成 []rune 即可,因为 []rune是按字符处理,兼容汉字
  arr1 := []rune(str)
  arr1[0] = '北'
  str = string(arr1)
  fmt.Println("str=", str)
}

 

posted @ 2019-08-14 23:57  我是一只忙碌的小青蛙  阅读(192)  评论(0编辑  收藏  举报