golang中的值类型和引用类型

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/love666666shen/article/details/99882528

值类型与引用类型

不管是Java还是golang中,都有值类型和引用类型的概念。在使用两者时,发现这两种语言之间还是有差异的。

值类型

值类型:这些类型的变量直接指向存在内存中的值,值类型的变量的值存储在栈中。当使用等号=将一个变量的值赋给另一个变量时,如 j = i ,实际上是在内存中将 i 的值进行了拷贝。可以通过 &i 获取变量 i 的内存地址。 值拷贝

引用类型

引用类型:引用类型拥有更复杂的存储结构:(1)通过make创建并分配内存 (2)初始化一系列属性:指针、长度、哈希分布、数据队列等。一个引用类型的变量r1存储的是r1的值所在的内存地址(数字),或内存地址中第一个元素所在的位置,这个内存地址被称之为指针,这个指针实际上也被存在另外的某一个变量中。

区别

值类型和引用类型两者之间的主要区别:拷贝操作和函数传参。

数组array和切片slice的实例

1)如下代码片段定义了一个数组a,它是值类型,复制给b是值拷贝copy,当b发生变化后a并不会发生任何变化,程序的执行结果如下所示:

//由 main 函数作为程序入口点启动
func main() {
	a :=[5]int{1,2,3,4,5}    //数组Array类型,带有具体的长度
	b := a   //值拷贝,等价于a :=[5]int{1,2,3,4,5}, b :=[5]int{1,2,3,4,5}
	b[2] = 6 //b :=[5]int{1,2,3,4,5},b[2]=8, b = [5]int{1,2,6,4,5}
	fmt.Println(a, b)
}

程序运行结果:
[1 2 3 4 5] [1 2 6 4 5]

2)切片则不然,由于切片是引用类型,其拷贝(赋值)属于址拷贝,所以其中一个元素的值发生变化,拷贝的另一方也会发生改变。
//由 main 函数作为程序入口点启动

func main() {
	a :=[]int{1,2,3,4,5}  //切片Slice类型,不带长度
	b := a                //址拷贝
	b[2] = 6              
	fmt.Println(a, b)
}

分析:
切片的底层数据结构其实是一个指针,切片a和b本质上指向同一个底层数组。
程序运行结果:
[1 2 6 4 5] [1 2 6 4 5]

golang中的struct类型

Golang中没有class关键字来定义类,对于事物的抽象以struct来定义,因此一个struct变量可以被看做一个类实例。但是这有别于java,因为struct在方法中传参时是值类型而非引用类型,所以当我们需要在方法内改变这个对象的字段值时,应该使用的是struct变量的指针,而非struct变量。例如:

type Student struct{
         Name string
}
 
func (s * Student) Set(name string){
              s.Name = name
}
func (s Student) Get()string{
           return s.Name
}

原文链接:https://blog.csdn.net/zerro99/article/details/11525757

由上可知:

  • 如果方法内部会修改当前对象的字段或改变其值,需要用指针。
  • 由于值传递是(内存)复制,因此,如果对象比较大,应该使用指针(地址),避免内存拷贝(值类型等变量指向内存中的值,如果有值类型变量存放大量元素,或造成内存的大量拷贝)。

注意:不见得使用指针就一定好过传值,因为按照 Go 的内存管理策略,涉及指针和引用的对象会被分配到 GC Heap 上。如果对象很 “小”,显然要比在栈上进行值拷贝 “耗费” 更多。

与Java差异

另外与java不同的一点,数组Array在golang里并不被当做引用类型传递,而是值类型传递。按照Golang的说法,Golang中所有的基本类型都属于值类型,但是有几个类型比较特殊,表现出引用类型的特征,分别是slice、map、channel、interface,除赋值以外它们都可以当做引用类型来使用。因此当我们这样做时,可以直接使用变量本身而不用指针:

type MyMap map[string]string
 
func (s  MyMap) Set(name,value string){
              s[name] = value
}

func (s MyMap) Get(name string)string{
           return s[name]
}

上面的例子由于MyMap是一个map,而map是引用类型,因此在方法中作为参数使用时可以直接使用MyMap来改变其值,而不用使用MyMap的指针,其实map本身是一个字典的指针。

猜你喜欢

转载自blog.csdn.net/love666666shen/article/details/99882528