2014-09-01 4 views
6

C'è un motivo per questo comportamento? Mi piacerebbe sapere cosa c'è di diverso nel livello di memoria. Il compilatore restituisce "impossibile prendere l'indirizzo letterale composito" mentre posso chiedergli esplicitamente di farlo.Perché l'istanziazione inline della variabile richiede esplicitamente di prendere l'indirizzo per richiamare il metodo del puntatore, mentre per una var esistente è implicito

Heres movimento parco giochi go playground link

u := User{"john"} 
fmt.Println(u.Name()) //implicit 

//fmt.Println(User{"john"}.Name()) //Error: cannot call pointer method on composite literal, cannot take the address of composite literal 
fmt.Println((&User{"jim"}).Name()) //explicit 

type User struct { 
    name string 
} 

func (u *User) Name() string { 
    return u.name 
} 

risposta

6

Perché un composite litteral è not addressable finché non è stato assegnato ad una variabile:

L'operando deve essere indirizzabile, cioè, sia una variabile, puntatore indiretto o operazione di indicizzazione delle sezioni; o un selettore di campo di un operando struct indirizzabile; o un'operazione di indicizzazione dell'array di un array indirizzabile.
Come eccezione al requisito di indirizzabilità, x può anche essere un letterale composito (eventualmente tra parentesi).

È possibile prendere l'indirizzo User{"jim"}: (&User{"jim"}) (puntatore letterale).
Ma non è possibile utilizzare direttamente il valore di User{"jim"} (valore letterale, non finché non viene assegnato a una variabile).
Scopri di più su this thread.


This thread aggiunge alla "espressione non è indirizzabile" questione:

Prendendo l'indirizzo di qualcosa, che fino a questo punto era ipotetica non indirizzabile (un'espressione che non accade essere radicato su un identificatore), non è semanticamente diverso dall'impostazione del valore di riferimento del puntatore di destinazione.
In altre parole, i seguenti sono equivalenti:

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

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

Poiché un'espressione viene gettato via non appena viene utilizzato, il indirizzo del suo valore (che spesso è interamente registro residente , e quindi in realtà non ha un indirizzo) è in ogni caso priva di significato, e l'unico vantaggio dal prendere il suo indirizzo è la convenienza sintattica dell'inferenza di tipo nelle dichiarazioni variabili (risparmiando al massimo una singola riga):

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

Un problema con fare espressioni arbitrarie indirizzabile:

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 breve: sarà chiaro (e quasi impossibile eseguire il debug) se si sta prendendo l'indirizzo di qualcosa che ti aspetti di essere indirizzabile, o quando stai prendendo l'indirizzo di una variabile intermedia implicita (che è molto spesso ciò che non vuoi).

+0

"Perché una litteria composta non è indirizzabile finché non è stata assegnata a una variabile" Vorrei sapere perché. Il thread non dà ragionamenti/argomenti soddisfacenti. – Gnani

+1

@Gnani perché il valore letterale in sé non è direttamente indirizzabile. & CompiteLiteral è. – VonC

2

C'è un motivo per questo comportamento?

La ragione per il comportamento è che c'è un'eccezione a indirizzabilità per quella specifica notazione e la ragione di tale eccezione è spiegata here da uno dei manutentori Go:

Sono speciale perchè abbiamo deciso che la notazione è stata utile sufficiente per i costruttori per meritare un caso speciale:

Taking the address of a composite literal (§Address operators) 
generates a unique pointer to an instance of the literal's value. 

http://golang.org/doc/go_spec.html#Composite_literals 

Russ


"Prendendo l'indirizzo di un letterale composito (operatori §Address) genera un puntatore unico a un'istanza del valore del letterale". Potresti elaborarlo?

penso che significa che la notazione notazione &Object{} è semplicemente un puntatore letterale ogni volta che viene eseguito crea una nuova istanza del valore e un nuovo puntatore viene creato che punti al nuovo valore. L'eccezione di indirizzamento deriva semplicemente dalla notazione di questo letterale, è diversa dalle altre indirizzabili perché non viene gestita dall'operatore &.

Vorrei una risposta simile a quella di jesse su il link "qui" che hai citato. Cioè per C. Qualcuno può confermare che per golang?

La mia ipotesi è questo che questa notazione è utile con l'analisi di fuga, che determina in fase di compilazione se un riferimento sfugge la funzione e determina se debba essere allocato sul cumulo o pila (più veloce). Da quello che ho capito, le variabili che hanno preso il loro indirizzo sono considerate candidate per l'analisi di fuga. Dal momento che uno degli obiettivi principali di Go è la compilazione veloce, penso che la creazione e il tracciamento dei riferimenti sia necessario per essere chiari.

Ad esempio, per Item{}.Method() la necessità di creare un puntatore e quindi eseguire analisi sfuggire al valore Item{} dipenderà dal tipo di ricevitore del Method() se è *Item o semplicemente Item complica inutilmente compilazione. Ecco perché si utilizza la notazione esplicita &Item{} per creare un *Item.

+0

"Perché è un'eccezione" non è gradevole. "Prendendo l'indirizzo di un letterale composito (§Address operatori) genera un puntatore univoco a un'istanza del valore del letterale." Potresti elaborarlo? Vorrei una risposta simile a quella di Jesse sul link "qui" che hai citato. Questo è per C. Qualcuno può confermarlo per il golang? – Gnani

+0

@Gnani ho aggiunto alcune possibili spiegazioni. –

+0

Riassunto VonC: i valori delle variabili non sono sempre ad indirizzi heap stabili; potrebbero essere in registri, essere in pila e essere spazzati via dopo il ritorno della funzione, o potrebbero essere valori di mappa che vengono spostati in memoria man mano che la mappa aumenta. – twotwotwo

Problemi correlati