2015-05-22 10 views
48

sono confusa sul motivo per cui questo non riesce a compilare con:Perché non è possibile l'interfaccia essere implementato con i ricevitori puntatore

Tipo impossibile affermazione: Faz non implementa Foo (metodo di Bar ha puntatore ricevitore)

se faccio il ricevitore per Faz.Bar un valore Faz, piuttosto che un puntatore Faz allora compila bene, ma ho pensato che era sempre meglio avere ricevitori puntatore in modo valori non vengono copiati in giro?

package main 

import (
    "log" 
) 

func main() { 
    foo := New().(Faz) 
    log.Println(foo) 
} 

type Foo interface { 
    Bar() string 
} 

func New() Foo { 
    return &Faz{} 
} 

type Faz struct { 
} 

func (f *Faz) Bar() string { 
    return `Bar` 
} 
+5

[Vedere questo post] (http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go). –

+3

Come una nota a margine: l'articolo a cui fa riferimento @KerrekSB mi ha aiutato a capire che quando Go si lamenta "MyFoo non implementa Foo (il metodo Bar ha ricevitore puntatore)", ciò non significa che non si può usare un ricevitore puntatore. Significa che o _none_ dei metodi di 'MyFoo' che implementano' Bar' dovrebbe avere ricevitori di puntatori, o _all_ di essi deve. Questo è un problema diverso da @ 0xor1, ma altri potrebbero trovare questa domanda perché stanno mixando i loro tipi di ricevitore (come me) e non capendo l'errore che stanno ottenendo. – Hephaestus

risposta

51

Perché non è *FazFaz.

func main() { 
    foo := New().(*Faz) 
    log.Println(foo) 
} 
+0

Sono sicuro di averlo provato: s, beh grazie :) – 0xor1

+4

Possono essere sia Faz che Faz ma devono tutti corrispondere. Definiscili tutti Faz se intendi restituire Faz {} o Faz se intendi restituire Faz {}. Il modo in cui mantengono lo stato è considerato un dettaglio di implementazione che fondamentalmente si nasconde all'utente. –

4

Penso che la risposta a questa domanda ha bisogno di un approccio più retrospettivo verso la grammatica, e come sarebbe la sua attuazione attraverso l'ingegneria del software. (scusi la semplificazione sopra)


Prima un rapido flashback di ciò che sono types?
Sono solo blocchi di memoria con la logica del compilatore in cima. Ciò che rende uno array diverso da un string è ciò che il compilatore ci consente di fare con quei blocchi di memoria. (Si pensi più profondo e si può cominciare a realizzare la vera differenza tra strongly typed e dynamically typed lingue.)

Ora successiva è necessario rendersi conto che i puntatori sono i loro propri tipi per dire.
*variable è un diverso blocco di memoria (di tipo noto) rispetto a variable. È solo che il compilatore presume sempre che il contenuto di *variable sarà sempre un indirizzo di un blocco di memoria di tipo a destra della dichiarazione insieme ad altre restrizioni/funzionalità che impone.

Quindi ricapitoliamo cos'è un'interfaccia.
Definizione pseudo-scientifica: un insieme di requisiti per qualsiasi cittadino di prima classe di un tipo specifico. Tradotto software Engineering- qualsiasi blocco di memoria (tipi) che ha la stessa struttura di memoria (ripercorrere structure packing) associato ad esso, come descritto in un contratto (interface) può essere passato intorno come con il nome tipo che il contratto menziona.


Ora si può cominciare a rendersi conto che quando si dice

func (f *Faz) Bar() string è 'blocco di s di memoria che una funzione, dove f' f s tipo è un puntatore a Faz

dove aree

func (f Faz) Bar() string è il blocco di memoria f, dove il tipo di f è Faz

Così, quando si sta dicendo che una variabile di tipo *Faz è soddisfacente un contratto, allora come si può supporre che una variabile di tipo Faz si qualificherà come tipo di interfaccia nel codice? Scegli chi soddisfa il tuo contratto e solo quel tipo può assumere il tipo di interfaccia nel tuo codice.

+0

Non sono d'accordo con la tua spiegazione, seguendo programma funziona (tipo * soddisfa foo String() definito per il tipo foo): pacchetto principale importazione ( \t "fmt" ) tipo foo struct {} func (f foo) String() stringa { \t ritorno "111" } func main() { \t f: = foo {} \t a: = & foo {} \t var s fmt.Stringer \t s = a \t s = f \t fmt.Println (f.String(), a.String(), s) } –

+0

Vedere https://golang.org/ref/spec#Method_sets –

Problemi correlati