在Golang中,*string和string有什么区别?

15

目的:了解Golang中*stringstring之间的区别。


尝试

func passArguments() {
    username := flag.String("user", "root", "Username for this server")
    flag.Parse()
    fmt.Printf("Your username is %q.", *username)
    fmt.Printf("Your username is %q.", username)
}

导致结果为:

Your username is "root".Your username is %!q(*string=0xc820072200)

但当字符串被赋给一个字符串变量时:

bla:=*username
fmt.Printf("Your username is %q.", bla)

它能够再次打印字符串:

Your username is "root".Your username is %!q(*string=0xc8200781f0).Your username is "root".

问题

  1. 为什么 *string != string,例如显示:"root" vs. %!q(*string=0xc8200781f0)
  2. 在什么其他情况下应该使用 *string 而不是 string,并说明原因?
  3. 为什么可以将 *string 分配给一个字符串变量,而字符串的显示不同,例如显示:"root" vs. %!q(*string=0xc8200781f0)

1
带有*的变量是指针,或者说是内存中的地址(可以将其视为变量所在房屋的邮寄地址)。请参考https://tour.golang.org/moretypes/1获取更多信息。 - ti7
1个回答

20

*string是一个指向字符串的指针。如果您不熟悉指针,可以将其视为保存另一个值的地址而不是该值本身的值(这是一种间接级别)。

当在类型中使用*时,它表示该类型的指针。*int是指向整数的指针。***bool是指向布尔值的指针的指针的指针。

flag.String返回一个指向字符串的指针,因为它可以修改字符串值(在调用flag.Parse之后),并且您可以使用解引用运算符检索该值 - 也就是说,在变量上使用*时,它会将其解引用或检索所指向的值,而不是变量本身的值(对于指针来说,这只是一个内存地址)。

因此,回答您的具体问题:

  1. fmt包中的%q动词理解字符串(和字节片),而不是指针,因此显示了表面上的无意义内容(当值与匹配动词 - 这里是%q - 的预期类型不符合时,fmt函数会显示%!q以及传递的实际类型和值)

  2. 很少使用指向字符串的指针。在Go中,字符串是不可变的 (https://golang.org/ref/spec#String_types),因此在像flag.String这样需要返回稍后将被修改的字符串时,必须返回一个指向字符串的指针。但在惯用的Go中很少看到这种情况。

  3. 您没有将*string(指向字符串的指针)分配给string。正如我之前提到的那样,你正在解引用*string变量,提取其string值。因此,实际上,您正在将string分配给string。尝试删除该行上的*,您将看到编译器错误消息。(实际上,由于使用了短变量声明符号:=,您不会看到编译器错误,但是您的变量将被声明为指向字符串的指针。请尝试以下更好地理解正在发生的事情:

    var s string
    s = username
    

那会导致编译器错误)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接