go中的值类型和引用类型

值类型和引用类型
值类型基本数据类型: int 系列, float 系列, bool, string 、数组和结构体struct
使用这些类型的变量直接指向存在内存中的值,值类型的变量的值存储在栈中。
当使用等号=将一个变量的值赋给另一个变量时,如 j = i ,实际上是在内存中将 i 的值进行了拷贝。
可以通过 &i 获取变量 i 的内存地址。  值拷贝

引用类型:指针、slice切片、map、管道chan、interface 等都是引用类型
引用类型拥有更复杂的存储结构:
(1)分配内存
(2)初始化一系列属性等一个引用类型的变量r1存储的是r1的值所在的内存地址(数字),或内存地址中第一个字所在的位置,这个内存地址被称之为指针,这个指针实际上也被存在另外的某一个字中。 
值类型在拷贝的时候传递的是值,当值发生变化不会影响原来的值。引用类型在拷贝时传递的是引用,当值发生变化时会影响原来的值。 

两者的主要区别:拷贝操作和函数传参。

下面是几个测试用例:

	i:=1
	fmt.Println("i的内存地址:",&i)//i的内存地址: 0xc042056080
	j:=i
	fmt.Println("j的内存地址:",&j)//j的内存地址: 0xc042056088
	j=2
	fmt.Println("j修改后的i值:",i)//j修改后的i值: 1
	fmt.Println("j修改后的j值:",j)//j修改后的j值: 2
	stu1:= Student{"Bob"}
	fmt.Println("stu1.name的内存地址:",&stu1.name)//stu1.name的内存地址: 0xc04204a1c0
	stu2:=stu1
	fmt.Println("stu2.name的内存地址:",&stu2.name)//stu2.name的内存地址: 0xc04204a1d0
	stu2.name="Jack"
	fmt.Println("stu2修改后的stu1值:",stu1)//stu2修改后的stu1值: {Bob}
	fmt.Println("stu2修改后的j值:",stu2)//stu2修改后的j值: {Jack}
	slice1:=[]int{1,2,3}
	fmt.Println("slice1 浅拷贝之前的值:",slice1)//slice1 浅拷贝之前的值: [1 2 3]

	slice2:=slice1
	fmt.Println("拷贝到slice2的值:",slice2)//拷贝到slice2的值: [1 2 3]

	fmt.Println("slice1[0]的内存地址:",&slice1[0])//slice1[0]的内存地址: 0xc0420540c0
	fmt.Println("slice2[0]的内存地址:",&slice2[0])//slice2[0]的内存地址: 0xc0420540c0

	slice2[0]=11
	fmt.Println("slice2[0]修改后slice1的值:",slice1)//slice2[0]修改后slice1的值: [11 2 3]
	fmt.Println("slice2[0]修改后slice2的值:",slice2)//slice2[0]修改后slice2的值: [11 2 3]
//由于数组是值类型,所以每一次复制都会拷贝它,
// 以及它的所有元素值。我在modify函数中修改的只是原数组的副本而已,
// 并不会对原数组造成任何影响。

func main() {
	array1 := [3]string{"a", "b", "c"}
	fmt.Printf("The array: %v\n", array1)//The array: [a b c]
	array2 := modifyArray(array1)
	fmt.Printf("The modified array: %v\n", array2)//The modified array: [a x c]
	fmt.Printf("The original array: %v\n", array1)//The original array: [a b c]
}

func modifyArray(a [3]string) [3]string {
	a[1] = "x"
	return a
}

//对于引用类型,比如:切片、字典、通道,像上面那样复制它们的值,
// 只会拷贝它们本身而已,并不会拷贝它们引用的底层数据。
// 也就是说,这时只是浅表复制,而不是深层复制。

func main() {
	array1 := []string{"a", "b", "c"}
	fmt.Printf("The array: %v\n", array1)//The array: [a b c]
	array2 := modifyArray(array1)
	fmt.Printf("The modified array: %v\n", array2)//The modified array: [a x c]
	fmt.Printf("The original array: %v\n", array1)//The original array: [a x c]
}

func modifyArray(a []string) []string {
	a[1] = "x"
	return a
}
//要注意,就算我们传入函数的是一个值类型的参数值,
// 但如果这个参数值中的某个元素是引用类型的,那么我们仍然要小心。

func main() {
	complexArray1 := [3][]string{
		[]string{"d", "e", "f"},
		[]string{"g", "h", "i"},
		[]string{"j", "k", "l"},
	}
	fmt.Printf("The array: %v\n", complexArray1)//The array: [a b c]
	array2 := modifyArray(complexArray1)
	fmt.Printf("The modified array: %v\n", array2)//The modified array: [[d e f] [1] [j k l]]
	fmt.Printf("The original array: %v\n", complexArray1)//The original array: [[d e f] [g x i] [j k l]]
}

func modifyArray(a [3][]string) [3][]string {
	a[1] = []string{"1"}
	return a
}
func main() {
	complexArray1 := [3][]string{
		[]string{"d", "e", "f"},
		[]string{"g", "h", "i"},
		[]string{"j", "k", "l"},
	}
	fmt.Printf("The array: %v\n", complexArray1)//The array: [a b c]
	array2 := modifyArray(complexArray1)
	fmt.Printf("The modified array: %v\n", array2)//The modified array: [[d e f] [g x i] [j k l]]
	fmt.Printf("The original array: %v\n", complexArray1)//The original array: [[d e f] [g x i] [j k l]]
}

func modifyArray(a [3][]string) [3][]string {
	a[1][1] = "x"
	return a
}

猜你喜欢

转载自blog.csdn.net/qq_20867981/article/details/86517900