Why are pointers of structs not printed like pointers of variables? [closed]

Consider the following code:

package main

import "fmt"

type Vertex struct {
    X, Y int
}

var (
    i = 10
    p = &i
    v = Vertex{1,2}
    q = &v
)

func main() {
    fmt.Println(p) // Outputs the memory location of the pointer
    fmt.Println(q) // Outputs the string &{1 2}
}

Why isn’t the memory location of pointer q printed, like it is with p?

This is because go allows you to use type pointers the same way you would use a regular var. So if you pass a pointer to a type the receiving function will operate on the original copy. If you pass a copy of the data than the modifications do not get applied back to the original var.

If the function explicitly asks for a pointer than you have to pass a pointer.

Here is a modification of your example that might clarify how go works.

package main

import "fmt"

type Vertex struct {
    X, Y int
}

var (
    i = 10
    p = &i
    v = Vertex{1, 2}
    q = &v
    t = &v.X
)

func main() {
    fmt.Println(p) // Outputs the memory location of the pointer
    fmt.Println(q) // Outputs the string &{1 2}
    fmt.Println(t)
    fmt.Println(&q)
}

This section from Effective GO

Pointers vs. Values

As we saw with ByteSize, methods can be defined for any named type (except
a pointer or an interface); the receiver does not have to be a
struct.

In the discussion of slices above, we wrote an Append function. We can
define it as a method on slices instead. To do this, we first
declare a named type to which we can bind the method, and then make
the receiver for the method a value of that type.

    type ByteSlice []byte

    func (slice ByteSlice) Append(data []byte) []byte {
    // Body exactly the same as the Append function defined above.
    }
This still requires the method to return the updated slice. We can
eliminate that clumsiness by redefining the method to take a pointer
to a ByteSlice as its receiver, so the method can overwrite the
caller's slice.

    func (p *ByteSlice) Append(data []byte) {
        slice := *p
        // Body as above, without the return.
        *p = slice
    }
In fact, we can do even better. If we modify our function so it looks like
a standard Write method, like this,

    func (p *ByteSlice) Write(data []byte) (n int, err error) {
        slice := *p
        // Again as above.
        *p = slice
        return len(data), nil
    }
then the type *ByteSlice satisfies the standard interface io.Writer, which
is handy. For instance, we can print into one.

    var b ByteSlice
    fmt.Fprintf(&b, "This hour has %d daysn", 7)
We pass the address of a ByteSlice because only *ByteSlice satisfies
io.Writer. The rule about pointers vs. values for receivers
is that value methods can be invoked on pointers and values, but
pointer methods can only be invoked on pointers.

This rule arises because pointer methods can modify the receiver; invoking
them on a value would cause the method to receive a copy of
the value, so any modifications would be discarded. The language
therefore disallows this mistake. There is a handy exception, though.
When the value is addressable, the language takes care of the common
case of invoking a pointer method on a value by inserting the address
operator automatically. In our example, the variable b is addressable,
so we can call its Write method with just b.Write. The compiler will
rewrite that to (&b).Write for us.

By the way, the idea of using Write on a slice of bytes is central to the
implementation of bytes.Buffer.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *