Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><code>vAge</code> is not considered as only a "value variable", because it's a known location in memory that stores a value of type <code>age</code>. Looking at <code>vAge</code> only as its value, <code>vAge.Set(10)</code> is <em>not</em> valid as an expression on its own, but because <code>vAge</code> is addressable, the spec declares that it's okay to treat the expression as shorthand for "get the address of vAge, and call Set on that" <em>at compile-time</em>, when we will be able to verify that <code>Set</code> is part of the method set for either <code>age</code> or <code>*age</code>. You're basically allowing the compiler to do a textual expansion on the original expression if it determines that it's necessary and possible.</p> <p>Meanwhile, the compiler will allow you to call <code>age(23).String()</code> but not <code>age(23).Set(10)</code>. In this case, we're working with a non-addressable value of type <code>age</code>. Since it's not valid to say <code>&amp;age(23)</code>, it can't be valid to say <code>(&amp;age(23)).Set(10)</code>; the compiler won't do that expansion.</p> <p>Looking at the Effective Go example, you're not directly calling <code>b.Write()</code> at the scope where we know <code>b</code>'s full type. You're instead making a temporary copy of <code>b</code> and trying to pass it off as a value of type <code>interface io.Writer()</code>. The problem is that the implementation of <code>Printf</code> doesn't know anything about the object being passed in except that it has promised it knows how to receive <code>Write()</code>, so it doesn't know to take a <code>byteSlice</code> and turn it into a <code>*ByteSlice</code> before calling the function. The decision of whether to address <code>b</code> has to happen at compile time, and <code>PrintF</code> was compiled with the precondition that its first argument would know how to receive <code>Write()</code> without being referenced.</p> <p>You may think that if the system knows how to take an <code>age</code> pointer and convert it to an <code>age</code> value, that it should be able to do the reverse; t doesn't really make sense to be able to, though. In the Effective Go example, if you were to pass <code>b</code> instead of <code>&amp;b</code>, you'd modify a slice that would no longer exist after PrintF returns, which is hardly useful. In my <code>age</code> example above, it literally makes no sense to take the value <code>23</code> and overwrite it with the value <code>10</code>. In the first case, it makes sense for the compiler to stop and ask the programmer what she really meant to do when handing <code>b</code> off. In the latter case, it of course makes sense for the compiler to refuse to modify a constant value.</p> <p>Furthermore, I don't think the system is dynamically extending <code>age</code>'s method set to <code>*age</code>; my wild guess is that pointer types are statically given a method for each of the base type's methods, which just dereferences the pointer and calls the base's method. It's safe to do this automatically, as nothing in a receive-by-value method can change the pointer anyway. In the other direction, it doesn't always make sense to extend a set of methods that are asking to modify data by wrapping them in a way that the data they modify disappears shortly thereafter. There are definitely cases where it makes sense to do this, but this needs to be decided explicitly by the programmer, and it makes sense for the compiler to stop and ask for such.</p> <p>tl;dr I think that the paragraph in Effective Go could use a bit of rewording (although I'm probably too long-winded to take the job), but it's correct. A pointer of type <code>*X</code> effectively has access to all of <code>X</code>'s methods, but 'X' does not have access to <code>*X</code>'s. Therefore, when determining whether an object can fulfill a given interface, <code>*X</code> is allowed to fulfill any interface <code>X</code> can, but the converse is not true. Furthermore, even though a variable of type <code>X</code> in scope is known to be addressable at compile-time--so the compiler can convert it to a <code>*X</code>--it will refuse to do so for the purposes of interface fulfillment because doing so may not make sense.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload