首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >由引用类型引发的概念的深入理解

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

作者头像
公众号-利志分享
发布2022-04-25 08:51:27
发布2022-04-25 08:51:27
2820
举报
文章被收录于专栏:利志分享利志分享

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

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

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

代码语言:javascript
复制
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",
  }
}

下面我们看下结果:

代码语言:javascript
复制
第一次:[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的样例,第一次是修改或者追加key和value,打印返回的值是修改成功的
第二次:map[a:b xx:xxxx]   这里是第二次去本身函数改变,返回的b本身是不修改的,这里也同样证明b本身不是引用的,b的值是有引用的

好了,那么来了,如何对引用类型修改本身,那其实很简单就是让他们传地址到函数中,在函数中修改,函数执行完了,变量在函数中变化之后会在函数外也体现出来

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

代码语言:javascript
复制
type slice struct {
  array unsafe.Pointer
  len   int
  cap   int
}

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

代码语言:javascript
复制
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的本身底层函数实现我就没有去了解了,后续有时间去尝试。

代码语言:javascript
复制
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的返回的结果


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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 利志分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档