2015-11-26 12 views
12

mam ten przykładowy kodmetoda Golang ze wskaźnikiem odbiornika

package main 

import (
    "fmt" 
) 

type IFace interface { 
    SetSomeField(newValue string) 
    GetSomeField() string 
} 

type Implementation struct { 
    someField string 
} 

func (i Implementation) GetSomeField() string { 
    return i.someField 
} 

func (i Implementation) SetSomeField(newValue string) { 
    i.someField = newValue 
} 

func Create() IFace { 
    obj := Implementation{someField: "Hello"} 
    return obj // <= Offending line 
} 

func main() { 
    a := Create() 
    a.SetSomeField("World") 
    fmt.Println(a.GetSomeField()) 
} 

SetSomeField nie działa zgodnie z oczekiwaniami, ponieważ jego odbiornik nie jest typu wskaźnika.

Gdybym zmienić metodę do odbiornika wskaźnik, co by się spodziewać do pracy, wygląda to tak:

func (i *Implementation) SetSomeField(newValue string) { ... 

Kompilacja prowadzi do następującego błędu:

prog.go:26: cannot use obj (type Implementation) as type IFace in return argument: 
Implementation does not implement IFace (GetSomeField method has pointer receiver) 

Jak można Mam struct implementować interfejs i zmienić wartość rzeczywistej instancji bez tworzenia kopii?

Oto hackable urywek: https://play.golang.org/p/ghW0mk0IuU

Już widziałem to pytanie In go (golang), how can you cast an interface pointer into a struct pointer?, ale nie mogę zobaczyć, jak to jest związane z tym przykładzie.

+0

Obie metody wymagają odbiorniki wskaźnik, jeszcze jesteś tylko wdrożenie część interfejsu. – elithrar

Odpowiedz

16

Twój wskaźnik do struktury powinien implementować interfejs. W ten sposób możesz modyfikować swoje pola.

Spójrz w jaki sposób modyfikować swój kod, aby to działa zgodnie z oczekiwaniami:

package main 

import (
    "fmt" 
) 

type IFace interface { 
    SetSomeField(newValue string) 
    GetSomeField() string 
} 

type Implementation struct { 
    someField string 
}  

func (i *Implementation) GetSomeField() string { 
    return i.someField 
} 

func (i *Implementation) SetSomeField(newValue string) { 
    i.someField = newValue 
} 

func Create() *Implementation { 
    return &Implementation{someField: "Hello"} 
} 

func main() { 
    var a IFace 
    a = Create() 
    a.SetSomeField("World") 
    fmt.Println(a.GetSomeField()) 
} 
+0

To było to. Wokół czaiła się inna metoda, która nie została zadeklarowana jako odbiornik wskaźnika. Dziękuję Ci – Atmocreations

9

Najprostszą odpowiedzią jest to, że nie można uzyskać struktury implementującej interfejs, podczas gdy SetSomeField działa tak, jak chcesz.

Jednak wskaźnik do struktury zaimplementuje interfejs, więc zmiana metody Create na wykonanie return &obj powinna sprawić, że wszystko będzie działać.

Podstawowym problemem jest to, że zmodyfikowana metoda SetSomeField nie znajduje się już w zestawie metod o numerze Implementation. Podczas gdy typ *Implementation będzie dziedziczył metody odbiorcze bez wskaźnika, odwrócenie nie jest prawdą.

Powodem tego jest sposób określania zmiennych interfejsu: jedynym sposobem uzyskania dostępu do wartości dynamicznej przechowywanej w zmiennej interfejsu jest jej skopiowanie. Jako przykład, wyobraźmy sobie, co następuje:

var impl Implementation 
var iface IFace = &impl 

w tym przypadku, to wezwanie do iface.SetSomeField prac, ponieważ może skopiować wskaźnik do wykorzystania jako odbiornika w wywołaniu metody. Jeśli bezpośrednio przechowywaliśmy strukturę w zmiennej interfejsowej, musimy utworzyć wskaźnik do tej struktury, aby zakończyć wywołanie metody. Po utworzeniu takiego wskaźnika możliwy jest dostęp do (i potencjalnie modyfikacja) wartości dynamicznej zmiennej interfejsu bez jej kopiowania.

Powiązane problemy