【问题标题】:What does the asterisk do in "Go"?“Go”中的星号有什么作用?
【发布时间】:2011-04-02 22:20:00
【问题描述】:

我是一名网络开发人员,希望扩大自己的视野,以便在整体编程方面做得更好。我做了一点 Java 和一些简单的 Android 应用程序。我现在正在研究像 C 和 Go 这样的低级语言(我必须说,到目前为止,它们有一些漂亮的语法和很棒的想法,尽管我可能缺乏经验,无法发表评论)。

所以是的,我一直在尝试理解 Go website 上的示例,并且在这样的示例中不断遇到一个特殊的星号字符:

s := "hello"
if s[1] != 'e' {
    os.Exit(1)
}
s = "good bye"
var p *string = &s
*p = "ciao"

另外,我刚刚注意到,&s 是什么?是引用赋值吗(我可能在这里使用 PHP 谈话)?

【问题讨论】:

  • 您会在 Go 和 C 等低级语言中看到星号和与号。
  • C 和 Go 可以使用称为指针的特殊变量,其中包含对象的内存地址。指针可以被传递,并且是一种将对象访问传递给其他代码的紧凑方式。在 Java 中,使用 new 运算符分配的对象的所有变量都是引用变量。引用与指针变量的概念相似,只是指针更明确。地址运算符可以在需要时获取对象的地址。可以用不同的地址重新分配指针变量。一个引用变量只能被初始化为一个地址。
  • ^ “5 分钟”教程不再存在 :-(

标签: go


【解决方案1】:

* 附加到类型 (*string) 表示指向该类型的指针。

* 附加到赋值中的变量 (*v = ...) 表示间接赋值。即改变变量指向的值。

* 附加到变量或表达式 (*v) 表示指针取消引用。也就是说,取变量指向的值。

& 附加到变量或表达式 (&v) 表示引用。也就是说,创建一个指向变量值或字段的指针。

【讨论】:

  • 值得澄清的是,对于*v = ... 情况,指针不会更改为指向具有不同值的内存中的新位置,但基础值会更改。
  • 另见 * 附加到结构 stackoverflow.com/questions/22693275/…
【解决方案2】:

我猜它的意思和 C 中的一样

p is a pointer to a string

语句var p *string = &s 会将s 对象的地址分配给p

下一行*p = "ciao" 会改变s 的内容

Language Design FAQ查看此链接

有趣的是,没有指针运算

为什么没有指针运算? 安全。无指针算术 可以创建一种语言 永远不能得出非法的 错误成功的地址。 编译器和硬件技术有 推进到循环的地步 使用数组索引可以是 使用指针作为循环高效 算术。此外,缺少指针 算术可以简化 垃圾的执行 收集器。

现在我要开始学习GO了!

【讨论】:

  • 学习围棋!我强烈推荐它。
  • 所以“p”被创建为一个指针,通过将它声明为类型“*string”并且&s指向变量s的内存位置。那么为什么我不能只说 p = "ciao" (而不是 *p)?这会产生一个名为“p”的新变量吗?
  • 当您说 *p = "ciao" 时,您是在说“获取 p 指向的内存并将其设置为等于 "ciao"”。如果你说 p = "ciao",你会试图说 "让 p 指向地址 "ciao",这是没有意义的,所以它不会编译。 p = &s 表示“使 p 指向 s 的地址”。也许这有帮助?
  • 为什么解释器不能在p *string = s时自动让p指向s的地址而不需要指定&s
  • 也推荐这篇短文Pointers in Go. Short tale of asterisk and ampersand,以帮助你理解Go中的指针。
【解决方案3】:

Go lang 地址、指针和类型:

s := "hello"      // type string
t := "bye"        // type string
u := 44           // type int
v := [2]int{1, 2} // type array
q := &s           // type pointer

所有这些Go 变量都有一个address in memory。它们之间的区别是字符串类型保存字符串值,int 类型保存整数值,指针类型保存地址。所以即使是保存地址的变量也有自己的内存地址。

指针:

在变量名计算其地址之前添加&。或者想,“这是我的地址,所以你知道在哪里可以找到我。”

// make p type pointer (to string only) and assign value to address of s
var p *string = &s // type *string
// or
q := &s // shorthand, same deal

在指针变量取消引用指向它所持有地址的指针之前添加*。或者想一想,“将操作传递给我的价值地址。”

*p = "ciao"   // change s, not p, the value of p remains the address of s

// j := *s    // error, s is not a pointer type, no address to redirect action to
// p = "ciao" // error, can't change to type string

p = &t        // change p, now points to address of t
//p = &u      // error, can't change to type *int

// make r type pointer (to a pointer which is a pointer to a string) and assign value to address of p
var r **string = &p // shorthand: r := &p

w := (  r == &p) // (  r evaluates to address of p) w = true
w =  ( *r == p ) // ( *r evaluates to value of p [address of t]) w = true
w =  (**r == t ) // (**r evaluates to value of t) w = true

// make n type pointer (to string) and assign value to address of t (deref'd p)
n := &*p
o := *&t // meaningless flip-flop, same as: o := t

// point y to array v
y := &v
z := (*y)[0] // dereference y, get first value of element, assign to z (z == 1)

去这里玩吧:http://play.golang.org/p/u3sPpYLfz7

【讨论】:

    【解决方案4】:

    这就是我的看法。不同的措辞可能有助于人们更好地理解它(您可以复制粘贴该代码并检查输出):

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        // declare a variable of type "int" with the default value "0"
        var y int
    
        // print the value of y "0"
        fmt.Println(y)
    
        // print the address of y, something like "0xc42008c0a0"
        fmt.Println(&y)
    
        // declare a variable of type "int pointer"
        // x may only hold addresses to variables of type "int"
        var x *int
    
        // y may not simply be assigned to x, like "x = y", because that 
        // would raise an error, since x is of type "int pointer", 
        // but y is of type "int"
    
        // assign address of y "0xc42008c0a0" as value to x
        x = &y
    
        // print the value of x "0xc42008c0a0" which is also the address of y
        fmt.Println(x)
    
        // print the address of x, something like "0xc420030028" 
        // (x and y have different addresses, obviously)
        fmt.Println(&x)
    
        // x is of type "int pointer" and holds an address to a variable of 
        // type "int" that holds the value "0", something like x -> y -> 0;
        // print the value of y "0" via x (dereference)
        fmt.Println(*x)
    
        // change the value of y via x
        *x = 1; /* same as */ y = 1
    
        // print value of y "1"
        fmt.Println(y); /* same as */ fmt.Println(*x)
    }
    

    【讨论】:

    • 使用公认的答案进行更深入的研究,但如果您正在寻找快速 101 到 Go 中的指针用法,请务必阅读此答案。
    【解决方案5】:

    * 字符用于在 C 和 Go 中定义指针。而不是一个实际值,该变量有一个指向值位置的地址。 & 运算符用于获取对象的地址。

    【讨论】:

    • 请注意 - 内存地址本身就是一个真实值。这就是为什么(在 C 中,但不是根据常见问题解答的 Go 语言)您可以对指针执行算术运算。
    • @monadic:真正的价值与执行算术有什么关系?
    【解决方案6】:

    我不知道 Go,但从语法上看,它似乎类似于 C - 那是一个指针。它类似于参考,但级别较低且功能更强大。它包含相关项目的内存地址。 &a 获取变量的内存地址,*a 取消引用它,获取内存地址处的值。

    另外,声明中的* 表示它是一个指针。

    是的,就像在 PHP 中一样,s 的值发生了变化,因为 p&s 指向同一个内存块。

    【讨论】:

    • OP 链接到的页面似乎强化了这一点。 “在前面放一个 & 给我们一个值的唯一实例的地址。”这个例子似乎符合这个解释。
    • 不过,PHP 比较并不准确。 & 可能代表了一个稍微相似的概念,但它们的实际用法有很大的不同(鉴于 PHP 不容易获取内存地址),说它是相同的概念可能具有欺骗性。
    • 我知道这不准确,PHP 网站本身说引用不是指针,但引用是我真正理解指针是什么的最接近的东西。
    • 它允许你做同样的事情,PHP 引用允许你以不同的方式做。我绝不是说 PHP 引用 = Go 指针。
    猜你喜欢
    • 2019-09-19
    • 2021-09-21
    相关资源
    最近更新 更多