V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
BryantBa
V2EX  ›  Go 编程语言

请教一个 Go 的小白问题

  •  
  •   BryantBa ·
    bryant-ba · 2022-01-12 15:19:46 +08:00 · 3644 次点击
    这是一个创建于 1048 天前的主题,其中的信息可能已经有所发展或是发生改变。

    请教一个 Go 的小白问题

    ( A ) func DoSomething(a *A) {
            b = a
        }
    
    ( B ) func DoSomething(a A) {
            b = &a
        }
       
    

    这两个函数调用的区别具体是什么呢

    25 条回复    2022-01-13 17:23:35 +08:00
    xidaduo
        1
    xidaduo  
       2022-01-12 15:32:37 +08:00
    A:引用传递
    B:值传递
    wunonglin
        2
    wunonglin  
       2022-01-12 15:47:03 +08:00
    A:传进来的是那个结构体的内存地址(吧?)
    B:通俗来说传入的 a 是 new 了一个一个零值的结构体,然后在把你传的结构赋值上去。
    hejw19970413
        3
    hejw19970413  
       2022-01-12 16:23:34 +08:00
    例如 a 现在的地址为 0x0000000001 值为 1
    ( A ) 函数中的 a 地址是 0x0000000002 但是 a 的值是 0x0000000001
    ( B ) 函数中的 a 地址是 0x0000000003 但是 a 的值是 1
    Arrowing
        4
    Arrowing  
       2022-01-12 16:53:04 +08:00
    *A 是 A 的指针类型
    labulaka521
        5
    labulaka521  
       2022-01-12 17:01:30 +08:00
    在函数里面修改 b 的值 然后在此函数外面看看 a 的值是否也被改了
    milk97
        6
    milk97  
       2022-01-12 17:30:34 +08:00
    (A) 是 point receiver, https://go.dev/tour/methods/4

    如果对 b 做修改,外面 a 指向的值也会变。

    ( B )这样写意义不大。`b = &a` 中的 a 已经是调用时参数 a 的一个 copy ,再取它的指针没什么意义,因为修改了 b 不是影响到外面的 a 。
    qq8331199
        7
    qq8331199  
       2022-01-12 18:23:43 +08:00
    @xidaduo 理论上说 go 是没用引用传递的,只有指针传递,指针传递和引用传递是有区别的
    DeWjjj
        8
    DeWjjj  
       2022-01-12 22:38:40 +08:00
    ...
    一个传进来的东西是指针类型,一个是传值进来取地址然后给 b 。
    这差异够大了吧,一个是标识符取地址,一个是指针本身。
    &a = 0x02 &c =0x01 c = 1 *a = 1 a=0x01.
    1.b = 0x01 = &c
    2.b = &a = 0x02
    DeWjjj
        9
    DeWjjj  
       2022-01-12 22:52:30 +08:00
    建议点说就是第一种你改*b 他能影响到外面。
    第二种你只能改 b 他影响不到外面。
    想要不改数据对外传递处理信息用第二种,想要处理信息顺手改外面传指针进去。
    mx8Y3o5w3M70LC4y
        10
    mx8Y3o5w3M70LC4y  
       2022-01-12 23:25:03 +08:00 via Android
    要明白这个问题,先要了解引用数据类型,是怎么在内存中存储的。一个 T 类型的对象 t ,实际上需要开辟两种不同的内存空间来存储,t 在栈内存中,而对应的值是在堆内存中。*T 是指向堆内存地址的指针;而&t ,则是栈内存中 t 的地址。
    voidmnwzp
        11
    voidmnwzp  
       2022-01-12 23:39:35 +08:00 via iPhone
    c 语言没学过?
    chenall
        12
    chenall  
       2022-01-13 04:08:58 +08:00 via Android
    A 这个原始值后续可能会改变,需要同步变化时用。
    后续 b=a

    B 干净调用,b 是 a 的副本,后续 a 和 b 没有交集。
    xsen
        13
    xsen  
       2022-01-13 07:00:20 +08:00
    A:指针传递,可修改其值
    B:值传递,不可修改

    对于 go 来说,若你想修改某个参数的值,就需要拿到其指针
    xsen
        14
    xsen  
       2022-01-13 07:01:13 +08:00
    与 c/c++中指针与值概念是一样的,只是用起来没有心理负担
    darknoll
        15
    darknoll  
       2022-01-13 09:45:03 +08:00
    go 里面没有引用传参,都是值传递
    sozengtao
        16
    sozengtao  
       2022-01-13 11:34:05 +08:00
    @darknoll 是的 。老哥说的对 。指针地址也是值 。仅此而已
    NeoZephyr
        17
    NeoZephyr  
       2022-01-13 14:00:53 +08:00
    B 属于脱裤子放屁了
    meiyoumingzi6
        18
    meiyoumingzi6  
       2022-01-13 14:23:42 +08:00
    0. 先解释 Golang 的值传递, 注意任何情况下都是值传递, 但是这个值可能是一个地址, 举个例子, 某东有卖螃蟹的, 但是很多是卖的螃蟹券, 我买了螃蟹券, 然后送了人, 那是不是可以说买了螃蟹送礼, 可以, 不过最终需要那个人自提而已
    1. 有没有办法证明 Golang 是值传递,
    ```golang
    package main

    import "fmt"
    type demo struct{}

    func test(arg interface{}) {
    fmt.Printf("in func test %p\n", &arg)
    }



    func main() {
    d := demo{}
    fmt.Printf("out of test %p\n", &d)
    test(d)

    fmt.Printf("out of test %p\n", &d)
    test(&d)

    s := []int{1,2,}
    fmt.Printf("out of test %p\n", s)
    test(s)

    m := map[string]int{"1":1}
    fmt.Printf("out of test %p\n", m)
    test(m)
    }

    /*
    out of test 0x116ce80
    in func test 0xc000010230
    out of test 0x116ce80
    in func test 0xc000010240
    out of test 0xc0000160c0
    in func test 0xc000010250
    out of test 0xc000074180
    in func test 0xc000010260
    */
    ```
    2. slice/map 是引用类型, 害, 你就把他当个螃蟹券
    3. 题中两个区别
    i). 开销不同, a 中值需要赋值一次地址, 开销很小, b 中需要复制一次结构体
    ii). 虽然看起来效果一样, 但是 b 中的 a 跟已经跟外面的 a 不是一个东西了, 因为有一次拷贝, 完完全全就是两个东西
    dany813
        19
    dany813  
       2022-01-13 14:31:21 +08:00
    学习了
    ixiaofeng
        20
    ixiaofeng  
       2022-01-13 14:43:25 +08:00
    目测这个问题是在看完 the way to go 以后发现的吧
    Tinywan
        21
    Tinywan  
       2022-01-13 15:11:57 +08:00
    @darknoll 指针不是 引用传参 ?
    chtcrack
        22
    chtcrack  
       2022-01-13 15:51:08 +08:00
    先学习*和&代表了啥.*是指针,&是取地址.学习 go 之前先去学一下 c 的指针那块内容,就不会被这个搞晕.
    int var_runoob = 10;
    int *p; // 定义指针变量
    p = &var_runoob;//取出 var_runoob 指向的地址赋值给 p
    printf("p 的值: %p\n", p);
    p 的值:0x7ffeeaae08d8
    BryantBa
        23
    BryantBa  
    OP
       2022-01-13 16:10:40 +08:00
    @ixiaofeng 雀食了
    BryantBa
        24
    BryantBa  
    OP
       2022-01-13 16:11:45 +08:00
    大佬们学习了,大学学 C 的时候就是指针谜,现在还是
    SimbaPeng
        25
    SimbaPeng  
       2022-01-13 17:23:35 +08:00
    @Tinywan

    golang 只有值传递
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3940 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 10:27 · PVG 18:27 · LAX 02:27 · JFK 05:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.