【问题标题】:In golang, what is the difference between & and *在golang中,&和*有什么区别
【发布时间】:2015-10-20 17:17:35
【问题描述】:

谁能解释 GO 语言中 & 和 * 之间的区别.. 并举例说明何时使用 & 和 * 来说明区别? 根据我的阅读,它们都与访问变量内存位置有关,但是我不确定何时使用 & 或 *。

【问题讨论】:

  • 很难用错一个,因为它通常不会编译。试一试,感受一下他们的所作所为:tour.golang.org/moretypes/1
  • 我赞同这个建议。我无法准确地说明这两个操作员的规则,例如规范中的内容以挽救我的生命,但只要我需要通过反复试验,我就会让它们工作。大多数情况下,如果错误,它将无法编译,因为在赋值的任一侧都有不兼容的类型。
  • 这能回答你的问题吗? What does the asterisk do in "Go"?

标签: go


【解决方案1】:

这是一个非常简单的示例,说明了如何使用&*。请注意,* 可用于两种不同的用途:1) 将变量声明为指针 2) 取消引用指针。

package main

import "fmt"

func main() {
    b := 6 

    var b_ptr *int // *int is used to declare variable
                   // b_ptr to be a pointer to an int

    b_ptr = &b     // b_ptr is assigned the value that is the
                   // address of where variable b is stored

    // Shorthand for the above two lines is:
    // b_ptr := &b

    fmt.Printf("address of b_ptr: %p\n", b_ptr)

    // We can use *b_ptr to get the value that is stored
    // at address b_ptr, known as dereferencing the pointer
    fmt.Printf("value stored at b_ptr: %d\n", *b_ptr)
    
}

结果:

address of b_ptr: 0xc82007c1f0
value stored at b_ptr: 6

【讨论】:

  • 在“ func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) ”的上下文中,为什么Request取消引用指针而ResponseWriter没有?
  • 该函数签名通常看起来像这样func(w http.ResponseWriter, r *http.Request),其中whttp.ResponseWriter 对象,r 是指向http.Request 对象的指针。在这种情况下没有取消引用。
  • 这是一个很好的例子,只需使用 bPtr 而不是 b_ptr,因为 golang 建议避免在变量声明中使用“_”
【解决方案2】:

这有助于我更好地理解,您可以在 Playground 中运行代码并试玩一下,看看它的行为链接:https://play.golang.org/p/c7jxLJkdRDd(如果将来链接失效,只需复制下面的粘贴代码)

package main

import (
    "fmt"
)

func main() {

    var a = 5
    var p = &a // copy by reference
    var x = a  // copy by value

    fmt.Println("a = ", a)   // a =  5
    fmt.Println("p = ", p)   // p =  0x10414020
    fmt.Println("*p = ", *p) // *p =  5
    fmt.Println("&p = ", &p) // &p =  0x1040c128
    fmt.Println("x = ", x)   // x =  5

    fmt.Println("\n Change *p = 3")
    *p = 3
    fmt.Println("a = ", a)   // a =  3
    fmt.Println("p = ", p)   // p =  0x10414020
    fmt.Println("*p = ", *p) // *p =  3
    fmt.Println("&p = ", &p) // &p =  0x1040c128
    fmt.Println("x = ", x)   // x =  5

    fmt.Println("\n Change a = 888")
    a = 888
    fmt.Println("a = ", a)   // a =  888
    fmt.Println("p = ", p)   // p =  0x10414020
    fmt.Println("*p = ", *p) // *p =  888
    fmt.Println("&p = ", &p) // &p =  0x1040c128
    fmt.Println("x = ", x)   // x =  5

    fmt.Println("\n Change x = 1")
    x = 1
    fmt.Println("a = ", a)   // a =  888
    fmt.Println("p = ", p)   // p =  0x10414020
    fmt.Println("*p = ", *p) // *p =  888
    fmt.Println("&p = ", &p) // &p =  0x1040c128
    fmt.Println("x = ", x)   // x =  1

    &p = 3 // error: Cannot assign to &p because this is the address of variable a
}

【讨论】:

    【解决方案3】:

    它们是相反的。如the "Address operators" section of the spec 中所述:

    对于T 类型的操作数x,地址操作&x 生成一个*T 类型的指针,指向x。 […]

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

    换句话说:& 接受一个变量(或其他可寻址实体)并返回一个指向它的指针,而 * 接受一个指针并返回它指向的东西(除非它是 nil,意味着它不指向任何东西)。

    【讨论】:

    • 术语更正:& 操作可能需要一个值,而不是一个变量——一个很好的例子是从文字中取出一个地址,就像在 v := &SomeType{} 中一样; * 运算符返回一个值,而不是变量。变量是名称;您可以在需要一个值来引用该值的上下文中使用它,但是指针解引用运算符返回一个值,并且该值可能没有绑定到它的变量。
    • @kostix:很好,谢谢;固定的。我太习惯于 Java 规范,其中任何左值都称为“变量”。 :-P
    【解决方案4】:

    & 是运营商的地址。 * 在某些情况下代表一个指针,在其他情况下它用作“取消引用运算符”。

    所以基本上,如果你这样做 p := &SometType{} 运算符的地址用于返回使用复合文字语句 SomeType{} 创建的对象的地址,如果我要删除它,我将不再有引用,而是将值直接分配给p。在这种情况下,p 将是 *SomeType,因为这是我使用的地址类型。如果我声明一个前面带有* 的类型,我将其指定为指向该类型的指针。

    现在剩下的最后一个用途是作为遵从运算符,根据我的经验,你在 Go 中不会使用这么多,但它在 C 和 C++ 中非常常见。这用于返回实际值,它通常是分配的杠杆。因为就像我有p 并且它是*SomeType 并且在本地我想分配给SomeType 的实例,那么我需要以下语句someType := *p 以便将值分配给我的值类型。

    希望解释有所帮助。这不是最技术性的,而是我的目标是提供对常见用途的理解。

    【讨论】:

      【解决方案5】:

      & 从变量中创建一个指针。

      *“获取”存储在指针指向的值。

      对于类型,var *type 表示“*var 属于 type 类型”(没有变量,它仅表示“指向 type 的指针” .

      【讨论】:

        【解决方案6】:

        &和*主要用在函数中:

        package main
        
        import (
            "fmt"
        )
        
        type Person struct {
            name     string
            ageYears int
            areDays  int
        }
        
        func main() {
            john := Person{name: "John", ageYears: 46}
            toDays(&john)
            fmt.Println(john) //{John 46 16790}
            toDays2(john)
            fmt.Println(john) //{John 46 16790}
        }
        
        func toDays(p *Person) {
            p.areDays = p.ageYears * 365
        }
        
        func toDays2(p Person) {
            p.areDays = -1
        }
        

        【讨论】:

          猜你喜欢
          • 2020-08-08
          • 2012-10-06
          • 1970-01-01
          • 1970-01-01
          • 2023-02-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多