由引用类型引发的概念的深入理解

共 2940字,需浏览 6分钟

 ·

2020-09-07 09:48

我们从百度百科上面看引用的概念:引用类型 由类型的实际值引用(类似于指针)表示的数据类型。如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值。

这里是什么意思呢,意思是假如一个a变量是数组,这个数组的类型是引用类型,a有a[0]='111','111'保存在另外一个数据结构b里面,这里的a[0]是指向的这个b数据的地址。

下面我们来通过例子理解一下。

package main
import ( "fmt")
func main() { //这里是初始化声明赋值一个a //a := []int{3, 4, 5} a := make([]int, 3) a[0] = 3 a[1] = 4 a[2] = 5 test(a) fmt.Println(a) test2(a) fmt.Println(a)
b := map[string]string{ "a": "b", } test3(b) fmt.Println(b) test4(b) fmt.Println(b)}
func test(a []int) { a[2] = 6}
func test2(a []int) { //a = append(a, 9) a = []int{8, 93, 3, 11} fmt.Println("test2 a", a)}
func test3(b map[string]string) { b["xx"] = "xxxx"}
func test4(b map[string]string) { b = map[string]string{ "888": "999", }}

下面我们看下结果:

第一次:[3 4 6]   这里是直接修改a的值,修改第二个值,打印是返回的值test2 a [8 93 3 11]    这里是在test2函数里面修改a的值,打印出来的第二次:[3 4 6]    这里是test2函数执行之后返回的结果,a本身没有变化,这里可以看出a本身不是引用的,但是a里面的值的变量是有引用的第一次:map[a:b xx:xxxx] 这里是map类型b的样例,第一次是修改或者追加keyvalue,打印返回的值是修改成功的第二次:map[a:b xx:xxxx]   这里是第二次去本身函数改变,返回的b本身是不修改的,这里也同样证明b本身不是引用的,b的值是有引用的
好了,那么来了,如何对引用类型修改本身,那其实很简单就是让他们传地址到函数中,在函数中修改,函数执行完了,变量在函数中变化之后会在函数外也体现出来

下面我们看一下a slice的底层实现结构体如下,如果我们直接使用它,它只有属性array是指向一个地址的

type slice struct {  array unsafe.Pointer  len   int  cap   int}

顺便我们了解下b map的底层实现结构体是什么,其实我们存的值是在buckets里面,也是一个指针。

type hmap struct {  // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.  // Make sure this stays in sync with the compiler's definition.  count     int // # live cells == size of map.  Must be first (used by len() builtin)  flags     uint8  B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)  noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details  hash0     uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields}

了确定这个引用类型的知识点,我特意去用java写了个例子,看看是不是语言通用的,java的本身底层函数实现我就没有去了解了,后续有时间去尝试。

import org.junit.Test;
public class Application { @Test public void main() { String[] str = {"xxx", "bbb"}; System.out.println("初始化数据:"+str[1]); test(str); System.out.println("第一次:"+str[1]); test2(str); System.out.println("第二次:"+str[1]); }
public void test(String[] str) { str[1] = "2"; }
public void test2(String[] str) { str = new String[]{"5", "6"}; }}

下面是java的返回的结果


初始化数据:bbb 初始化是bbb第一次:2   修改函数里面的值,返回的是修改的值第二次:2   这里是本str本身进行修改,修改完了之后,函数外之后执行没有变化。

好了,到这里我们对引用类型有了深入的理解了,后面有对底层slice和map的实现进行进一步了解和学习。





推荐阅读



学习交流 Go 语言,扫码回复「进群」即可


站长 polarisxu

自己的原创文章

不限于 Go 技术

职场和创业经验


Go语言中文网

每天为你

分享 Go 知识

Go爱好者值得关注


浏览 12
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报