Why does inline instantiation of variable requires explicitly taking the address of it to call pointer method, while for a existing var its implict

前端 未结 2 1859
星月不相逢
星月不相逢 2021-02-02 01:25

Is there a reason for this behaviour? I would like to know what is different in the memory level. The compiler returns \"cannot take the address of composite literal\" while i c

2条回答
  •  花落未央
    2021-02-02 01:55

    Because a composite litteral is not addressable until it's been assigned to a variable:

    The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array.
    As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.

    You can take the address to User{"jim"}: (&User{"jim"}) (literal pointer).
    But you cannot directly use the value of User{"jim"} (literal value, not until it is assign to a variable).
    See more in this thread.


    This thread adds to the"Expression isn't addressable" issue:

    Taking the address of something, that up to this hypothetical point was not addressable (an expression that doesn't happen to be rooted to an identifier), is semantically no different then setting the dereferenced value of the destination pointer.
    In other words, the following are equivalent:

    var x *int
    *x = (2 * 3) + 4
    
    var x *int
    x = &((2 * 3) + 4)
    

    Since an expression is thrown away as soon as it's used, the address of its value (which often is entirely register-resident, and thus doesn't actually have an address) is entirely meaningless in any case, and the only benefit from taking it's address is the syntactic convenience of type-inference in variable declarations (saving at most a single line):

    x := &((2 * 3) + 4)
    

    A problem with making arbitrary expressions addressable:

    m := map[int]int{1:2}
    x := &m[1]
    x = 3
    fmt.Println("x is", x, "while m[1] is", m[1])
    // will print `x is 3 while m[1] is 2`
    

    In short: it'll be unclear (and nigh impossible to debug) whether you're taking the address of something you expect to be addressable, or when you're taking the address of an implicit intermediate var (which is very often what you don't want).

提交回复
热议问题