【问题标题】:Modifying data via pointers通过指针修改数据
【发布时间】:2020-04-16 08:28:18
【问题描述】:

https://play.golang.org/p/DOhYaiH53Ek

我不理解*&p 操作,也不理解作为int() value NOT a memory address 的指针*p 如何能够修改其valuevalueX = valueY。我知道我一定是误解了某些东西,但这段代码从字面上看似乎是自相矛盾的。

//point

package main

import "reflect"

var pt int = 27

func main() {
    println(reflect.TypeOf(pt))
    println("pt = ", pt)   //value of pt
    println("&pt = ", &pt) //memory address of pt
    updatePointer(&pt)
    println("pt = ", pt) //value of pt
}

func updatePointer(p *int) { //requires memory address of an int
    println("&p = ", &p)                                //memory address of p
    println("p = ", p)                                  //memory address of pt
    println("*p before = ", *p)                         //value of pt
    println(*p == 27)                                   //true
    *p = 14                                             //27 = 14??????????
    println("*p =", *p)                                 //value of pt
    println(reflect.TypeOf(&pt) == reflect.TypeOf(*&p)) //true!!!?????
    println("*&p = ", *&p)                              //memory address which p's memory address evals to???? 0x800 (p) -> 0x900 (pt) = 0x800 (p)?
}

/*
Why can't I do the following?

func updatePointer(p *int){
    p = 14
    //OR
    &p = 14
    //OR
    *&p = 14
}
*/

【问题讨论】:

    标签: pointers go variable-assignment assignment-operator


    【解决方案1】:

    简化。例如,

    package main
    
    import "fmt"
    
    func f(q *int) {
        fmt.Println(*q, q, &q, "f")
        *q = 14
        fmt.Println(*q, q, &q, "f")
    }
    
    func main() {
        var i int = 27
        var p *int = &i
        fmt.Println(*p, p, &p, i, "main")
        f(p)
        fmt.Println(*p, p, &p, i, "main")
    }
    

    输出:

    27 0x40e020 0x40c138 27 main
    27 0x40e020 0x40c148 f
    14 0x40e020 0x40c148 f
    14 0x40e020 0x40c138 14 main
    

    错误:

    /*
    func g(r *int) {
        // cannot use 14 (type int) as type *int in assignment
        r = 14
        // cannot assign to &r
        &r = 14
        // cannot use 14 (type int) as type *int in assignment
        *(&r) = 14
    }
    */
    

    游乐场:https://play.golang.org/p/Hwe3anFBTfD


    在 Go 中,所有参数都按值传递,就像通过赋值一样。指向 int i 的指针 p 按值 (q = p) 传递给函数 f。指针qp的副本,用于修改i*q = 14*q的值,将*int类型解引用为int类型。


    函数g 编译器错误消息解释了为什么这些语句是非法的。例如,*&r = 14*(&r) = 14r = 14cannot use 14 (type int) as type *int in assignmentr 是类型 *int


    参考资料:

    A Tour of Go

    The Go Programming Language Specification

    【讨论】:

      【解决方案2】:

      考虑到*&p,首先让我们简化示例(删除所有不相关的内容)

      var pt int = 27
      p := &pt // because &pt is passed as the argument into updatePointer
      *p = 14  // This assigns 14 to whatever p points to (i.e. pt)
      println(reflect.TypeOf(&pt) == reflect.TypeOf(*&p))
      

      *& 什么都不做(而且我认为没有理由在实际应用程序中使用它);该语句获取 p 的地址(&p 位),然后获取结果指向的地址(p)。所以这个要改写

      println(reflect.TypeOf(&pt) == reflect.TypeOf(p))
      

      p 指向pt 所以p == &pt(根据定义,这意味着*p == pt)。这意味着它们是相同的东西,所以当然会具有相同的类型。

      那么为什么*p = 14 有效?你说“*p 是一个 int() 值而不是内存地址能够修改它的值”,但这并不是 the spec 所说的:

      对于指针类型 *T 的操作数 x,指针间接 *x 表示 x 指向的类型 T 的变量。如果 x 为零,则 尝试评估 *x 将导致运行时恐慌。

      所以*p = 14 的意思是将 p 指向的变量设置为 14。

      现在让我们看看你的第二个问题:

      // Why can't I do the following?
      
      func updatePointer(p *int){
          p = 14
          //OR
          &p = 14
          //OR
          *&p = 14
      }
      

      所以 p 是一个指向整数的指针(这就是 *int 的意思)。说 p = 14 是试图将指针(而不是 int)设置为值 14。14 是 int 而不是指针,因此编译器错误 cannot use 14 (type int) as type *int in assignment

      &p = 14 表示将 p 的地址设置为 14。p*int,因此获取地址将为您提供 **int(指向 int 指针的指针)。您将得到的编译器错误是cannot assign to &p,这是因为&p 的结果不是addressable。你可以通过说来解决这个问题

      x := &p
      x = 14
      

      根据我上面所说的内容,这会给您带来您可能期望的错误:cannot use 14 (type int) as type **int in assignment

      *&p = 14p=14 基本相同(它获取 p 的地址,然后获取任何结果指向的 whis 将是 p)。

      指针可能会让人很困惑(尤其是在人为的示例中),this article 可能会帮助您理解。

      【讨论】:

        猜你喜欢
        • 2016-12-18
        • 2011-06-23
        • 2011-01-31
        • 1970-01-01
        • 2010-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-21
        相关资源
        最近更新 更多