• Golang的Slice的小细节


    一、为什么说切片是引用类型,切片在函数之中传递会影响原有值

    Go类型:基本类型(bool string int array)、引用类型(切片\map\interface\func\channel)、 结构类型、 自定义类型

    引用类型,标头值里包含一个指 针,指向底层的数据结构,当我们在函数中传递引用类型时,其实传递的是这个标头值的副本,它所指向的底层结构并没有被复制传递,这也是引用类型传递高效的原因

    比如切片(引用类型)和数组(基本类型)

    1、切片原理,可以知道切片其实内部是一个unsafearray ,非线程安全数组的指针,对切片操作其实是对这个内部的数组进行操作(容量变更会重新生成新的数组替换)

    2、函数之间传递变量,如下面的p变量,他们的地址不是同一个,因为p变量的值会交给S函数,S函数内部会重新生成一个变量存储它,只是由于存储的是切片指向的同一个底层数组的指针,所以才会带来原有值的变化

    也就是说:

    func TestSliceTrans(t *testing.T) {
        var p = []string{"a"}
        fmt.Printf("TestSliceTrans %p %s \n", &p, p)
        S(p)
        fmt.Printf("TestSliceTrans %p %s \n", &p, p)
    }
    
    func S(l []string) {
        l[0] = "b"
        fmt.Printf("S %p %s \n", &l, l)
    }

    输出

    TestSliceTrans 0xc0000be180 [a] 
    S 0xc0000be1b0 [b] 
    TestSliceTrans 0xc0000be180 [b] 

    即使 S 函数里面的 l 的指针和 上层不一致,但是这个切片指向的内部的数组是同一个,所以 S 函数内更改了切片的值

    func P(p Person) {
        p.Name = "rose"
        fmt.Printf("P %p\n", &p)
    }
    
    func TestSliceTrans(t *testing.T) {
        var p = []string{"a"}
        fmt.Printf("TestSliceTrans %p %s \n", &p, p)
        S(p)
        fmt.Printf("TestSliceTrans %p %s \n", &p, p)
    }
    
    func S(l []string) {
        l = append(l, "b")
        fmt.Printf("S %p %s \n", &l, l)
    }

    输出

    TestSliceTrans 0xc00000e198 [a] 
    S 0xc00000e1c8 [a b] 
    TestSliceTrans 0xc00000e198 [a] 

    二、为什么切片传递之中有时候不会影响原有的值

    为什么这里的切片值没有被改变呢,这里就涉及切片的append的时候的扩容方式,在append的时候切片会将底层指向的数组更换为新的数组,也就是说 append之后对之前的底层指向的数组是没有做操作的,所以不会改变值

    结论:函数操作之中,判定被调用者是否会变更原来的变量的值,本质上是判定两个函数之间的变量内部存储的是指针还是值,也就是说判定下游函数操作数据的时候操作的是指针还是值,而对于切片、chan(两个底层都是一个变量的指针)那么传递过去的话,变量的操作如果没有变更底层的指针的话操作的就是同一个变量

     

    参考地址:

    https://blog.csdn.net/weixin_52690231/article/details/123967274#11_5

    https://www.jianshu.com/p/fbcaa36cff1c Map实现原理

  • 相关阅读:
    亿级 Web 系统的容错性建设实践
    Spring 4支持的Java 8新特性一览
    Java多线程干货系列—(一)Java多线程基础
    Sublime Text 2 实用快捷键(Mac OS X)
    spring-事务管理
    100 个 Linux 常用命令大全
    这些年MAC下我常用的那些快捷键
    Java 容器源码分析之HashMap多线程并发问题分析
    MySQL索引结构--由 B-/B+树看
    Java 容器之 Connection栈队列及一些常用
  • 原文地址:https://www.cnblogs.com/xuweiqiang/p/16389752.html
Copyright © 2020-2023  润新知