21

Aim: understanding the difference between *string and string in Golang


Attempt

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)
}

results in:

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

but when the *string is assigned to a string:

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

it is able to print the string again:

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

Questions

  1. Why is a *string != string, e.g. display of: "root" vs. %!q(*string=0xc8200781f0)?
  2. In what other cases should a *string be used instead of a string and why?
  3. Why is it possible to assign a *string to a string variable, while the display of the string is different, e.g. display of: "root" vs. %!q(*string=0xc8200781f0)?
1
  • 1
    Variables denoted with a * are pointers, or an address in memory (think of it as a mailing address where a variable is a house). Refer to tour.golang.org/moretypes/1 for more. Commented Nov 15, 2015 at 17:51

1 Answer 1

24

A *string is a pointer to a string. If you're not familiar with pointers, let's just say that it's a value that holds the address of another value, instead of the value itself (it's a level of indirection).

When a * is used in a type, it denotes a pointer to that type. *int is a pointer to an integer. ***bool is a pointer to a pointer to a pointer to a bool.

flag.String returns a pointer to a string because it it can then modify the string value (after the call to flag.Parse) and you are able to retrieve that value using the dereference operator - that is, when using * on a variable, it dereferences it, or retrieves the value pointed to instead of the value of the variable itself (which in the case of a pointer would just be a memory address).

So to answer your specific questions:

  1. the %q verb in the fmt package understands strings (and slices of bytes), not pointers, hence the apparent gibberish displayed (when a value is not of the expected type for the matching verb - here %q - the fmt functions display %!q along with the actual type and value passed)

  2. A pointer to a string is very rarely used. A string in Go is immutable (https://golang.org/ref/spec#String_types) so in cases like flag.String where you need to return a string that will be mutated later on, you have to return a pointer to a string. But you won't see that very often in idiomatic Go.

  3. You are not assigning a *string (pointer to a string) to a string. What you are doing, as I mentioned earlier, is dereferencing the *string variable, extracting its string value. So you are in fact assigning a string to a string. Try removing the * on that line, you'll see the compiler error message. (actually, because you're using the short variable declaration notation, :=, you won't see a compiler error, but your variable will be declared as a pointer-to-a-string. Try this instead, to better understand what's going on:

    var s string
    s = username
    

That will raise the compiler error).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.