golang中的切片

1. 切片中追加数据,如果没有扩容,内存地址不发生变化

 

 

	// 1. 切片中追加数据,如果不扩容的话,内存地址不发生变化
	v1 := make([]int, 1, 3)
	v2 := append(v1, 55)
	fmt.Println(v1, v2)
	fmt.Printf("%p, %p\n", &v1[0], &v2[0])
	v1[0] = 999
	fmt.Println(v1, v2)
	fmt.Printf("%p, %p\n", &v1[0], &v2[0])

	// 有一个切片,请往切片中追加一个数据
	v3 := make([]int, 1, 3)
	v3 = append(v3, 999)
	fmt.Println(v3)

2.  切片中追加数据,如果需要扩容的话,内存中就会拷贝一份出来,内存地址也就发生了变化

 

注意:扩容前和扩容后内存地址是不同的。

 3. 切片中的常见操作

package main

import (
	"fmt"
	"reflect"
)

func main() {
	// 1. 长度和容量
	v1 := []int{11, 22, 33}
	fmt.Println(len(v1), cap(v1))

	//2. 索引
	s1 := []string{"alex", "李杰", "老男孩"}
	fmt.Println(s1[0], s1[1], s1[2])
	s2 := make([]int, 2, 5)
	fmt.Println(s2[0], s2[1])
	s2[0] = 999
	fmt.Println(s2)

	// 3. 切片,通过切片切出来的数据和原切片内部存储的数据地址相同
	v2 := []int{11, 22, 33, 44, 55, 66}
	v3 := v2[1:3]
	fmt.Println(v3, reflect.TypeOf(v3))
	fmt.Printf("%p,%p\n", &v2[1], &v3[0])
	fmt.Printf("%p,%p\n", &v2[2], &v3[1])

	// 4. 追加
	v4 := []int{11, 22, 33}
	v5 := append(v4, 999, 888, 777) // 扩容了
	fmt.Println(v4, v5, cap(v5))
	v5 = append(v5, []int{66, 55}...) // append第二个参数可以放一个切片
	fmt.Println(v5, cap(v5))

	// 5. 删除
	v6 := []int{11, 22, 33, 44, 55, 66}
	deleteIndex := 2
	result := append(v6[:deleteIndex], v6[deleteIndex+1:]...)
	// [11 22 44 55 66 66] [11 22 44 55 66]
	fmt.Println(v6, result)
	fmt.Println(len(v6), cap(v6), len(result), cap(result))
	// 使用切片时不太会使用删除。1. 效率低 2. 修改了原切片的值, 建议使用链表
	// 删除方式2:不修改原来切片的值,重新声明一个切片
	//ret2 := make([]int, 0, len(v6)-1)
	//ret2 = append(ret2, v6[:deleteIndex]...)
	//ret2 = append(ret2, v6[deleteIndex+1:]...)
	//fmt.Println(v6, ret2)
	//fmt.Printf("%p,%p\n", &v6[0], &ret2[0])

	// 6. 插入
	v7 := []int{11, 22, 33, 44, 55, 66}
	insertIndex := 3 // 在索引3的位置插入99
	result1 := make([]int, 0, len(v7)+1)
	result1 = append(result1, v7[:insertIndex]...)
	result1 = append(result1, 99)
	result1 = append(result1, v7[insertIndex:]...)
	fmt.Println(v7)
	fmt.Println(result1)
	fmt.Printf("%p,%p\n", &v7[0], &result1[0])
	// 注意:效率低下,建议使用链表

	// 7. 循环
	v8 := []int{11, 22, 33, 44, 55, 66}
	for i, v := range v8 {
		fmt.Println(i, v)
	}

}

  

 4.  嵌套

	v1 := [][]int{{11, 222, 88, 99}, {33, 44}}
	fmt.Println(v1)
	v2 := [][2]int{{11, 22}, {33, 44}, {55, 66}}
	fmt.Println(v2)

	v1[0][3] = 1111
	fmt.Println(v1)
	v2[1][1] = 4444
	fmt.Println(v2)

5. 变量赋值到底赋值数据吗?

(1)不可修改类型

  

// 整型,数据复制了一份
	v1 := 1
	v2 := v1
	fmt.Printf("%p, %p\n", &v1, &v2)

	// 布尔,数据复制了一份
	b1 := false
	b2 := b1
	fmt.Printf("%p, %p\n", &b1, &b2)

	// 浮点型,数据复制了一份
	f1 := 3.14
	f2 := f1
	fmt.Printf("%p, %p\n", &f1, &f2)

	// 字符串型,数据复制了一份
	// 只是复制了字符串的长度和指针地址,而并没有复制字符串本身的数据
	// 同时:字符串内部元素是不可被修改的
	s1 := "武沛齐"
	s2 := s1
	fmt.Printf("%p, %p\n", &s1, &s2)
     // 数组,数据复制了一份
      v1 := [2]int{6, 9}
     v2 := v1
     fmt.Printf("%p, %p\n", &v1, &v2)
     fmt.Println(&v1[0], &v2[0])

(2)可变类型

	// 切片,数组不会复制,复制的只是切片的内存地址
	v1 := []int{6, 9}
	v2 := v1
	fmt.Printf("%p, %p\n", &v1, &v2)
	fmt.Println(&v1[0], &v2[0])  // 0xc0000aa070 0xc0000aa070

	// 如果扩容,那么内部存储数据的数组就会重新开辟区域
	v1 = append(v1, 999)
	fmt.Println(v1, v2)
	fmt.Println(&v1[0], &v2[0])  // 0xc0000a8080 0xc0000aa070

  总结:目前所学的所有数据类型中,在修改切片的内部元素时,会造成所有的赋值的变量同时修改(不扩容)

  扩展:"引用类型和值类型",官方不建议这么说,如果这样理解的话:切片是引用类型,整型、布尔、浮点型、字符串、数组都是值类型。

6. 切片练习题

package main

import "fmt"

func main() {

     
	// 嵌套1
	v1 := [][]int{make([]int, 2, 5), make([]int, 2, 5)}
	v2 := append(v1[0], 99)
	v2[0] = 69
	fmt.Println(v1)  // [[69 0], [0 0]]
	fmt.Println(v2)  // [69 0 99]  

	// 嵌套2
	//v1 := [][]int{make([]int, 2, 5), make([]int, 2, 5)}
	//v2 := append(v1[0][1:], 99)
	//v2[0] = 69
	//
	//fmt.Println(v1)  // [[0, 69], [0, 0]]
	//fmt.Println(v2)  // [69 99]

}

 

7. 切片和数组的区别?

(1)切片使用变量赋值的时候,两个切片变量使用的是同一块数据内存,而数组使用变量赋值的时候,两个数组变量使用的是不同内存

(2)数组是定长的,而切片是可变长的动态数组,而且切片定义时可以指定长度和容量

 

8. new和make的却别?

(1)new返回的是一个指针,而make返回的是一个对象

(2)new也帮助我们进行了初始化,整型初始化值是0,而make在它的内部也可以设置默认长度和默认容量。

 

9. 切片当做函数参数传递时,长度复制(各是各的),值是复制的底层数组的指针

也就是说,长度互不影响,值在不扩容的前提下可以互相影响

package main

import (
	"fmt"
	"time"
)

func main() {
	s := make([]int, 0, 10)
	go addValue(s)  // 使用协程来查看当此函数中对slice对底层数组修改时也会影响其它slice引用的底层数组
	time.Sleep(time.Second)
	s = append(s, 100, 200)
	fmt.Println("第二次打印:", "第一个元素的值:", s[0], "数组地址:", &s[0], "切片长度:", len(s), "切片容量:", cap(s), "切片值", s)
	time.Sleep(time.Second * 3)
}
func addValue(list []int) {
	list = append(list, 1, 2, 3, 4)
	fmt.Println("第一次打印:", "第一个元素的值:", list[0], "数组地址:", &list[0], "切片长度:", len(list), "切片容量:", cap(list), "切片值", list)
	time.Sleep(2 * time.Second)
	fmt.Println("第三次打印:", "第一个元素的值:", list[0], "数组地址:", &list[0], "切片长度:", len(list), "切片容量:", cap(list), "切片值", list)
}

/*
第一次打印: 第一个元素的值: 1 数组地址: 0xc00012e0f0 切片长度: 4 切片容量: 10 切片值 [1 2 3 4]
第二次打印: 第一个元素的值: 100 数组地址: 0xc00012e0f0 切片长度: 2 切片容量: 10 切片值 [100 200]
第三次打印: 第一个元素的值: 100 数组地址: 0xc00012e0f0 切片长度: 4 切片容量: 10 切片值 [100 200 3 4]
*/

  

 

posted @ 2021-10-07 11:41  专职  阅读(282)  评论(0编辑  收藏  举报