2013-09-07 31 views
29

Szukam porady na temat najlepszego sposobu na oczyszczenie następującej struktury. Wiem, że Go nie ma statycznych metod i zwykle jest to better to encapsulate functionality in a separate package. Moje typy struktur odwołują się do siebie, więc nie można ich zadeklarować w osobnych pakietach z powodu importu cyklicznego.Go: "Statyczny" projekt metody

type Payment struct { 
    User *User 
} 

type User struct { 
    Payments *[]Payments 
} 

func (u *User) Get(id int) *User { 
    // Returns the user with the given id 
} 

func (p *Payment) Get(id int) *Payment { 
    // Returns the payment with the given id 
} 

Ale jeśli chcę, aby załadować użytkownika lub zapłatę, po prostu wyrzucać odbiornika:

var u *User 
user := u.Get(585) 

mogłem przestrzeni nazw z funkcji siebie, co wydaje mi się nieczystego

func GetUser(id int) *User { 
    // Returns the user with the given id 
} 

func GetPayment(id int) *Payment { 
    // Returns the payment with the given id 
} 

Naprawdę chciałbym móc po prostu zadzwonić pod numer .Get lub podobny na struct bez wpisywania nazwy struktury w samej funkcji. Jaki jest idiomatyczny sposób na zrobienie tego?

Odpowiedz

23

GetUser() i GetPayment() uderz mnie jako idealnie jasne i idiomatyczne. Nie jestem pewien, co uważasz za nieczyste.

Wywołaniena strukturze do zwrócenia kolejnej struktury jest rzeczą, która uderza mnie jako bardzo dziwną, niejasną i jednoznaczną.

Myślę, że to może być przypadek trzymania się idiomu i ufania, że ​​się do tego przyzwyczaisz.

+2

Tak, znajduję '.Get()' na strukturze, które odrzucam jeszcze bardziej nieczyste. Dla mnie 'User.Get()' jest najczystszy; jeśli 'GetUser' jest najbliższym przybliżeniem, które mogę uzyskać, wezmę to. – ash

+1

@ash Tak, uważam, że jest najbliżej, i najbardziej idiomatyczny sposób na zrobienie tego. –

+0

Nie można tworzyć frameworka i bibliotek przy użyciu GetUser i GetPayment – rocketspacer

10

o funkcji Get jest idealnie w porządku; w żaden sposób nie jest to unidiomatic.

func (u *User) Get(id int) *User nie ma żadnego sensu, jednak powinno być func (u *User) Get(id int) error. Jedyne, czego nam brakuje to to, że możesz zdefiniować odbiornik metody na wskaźniku, a następnie wewnątrz tej metody, usunąć wskaźnik, aby nadpisał to, co wskazuje.

Jak to:

// Returns the user with the given id 
func (u *User) Get(id int) error { 
    *u = User{ ... } // dereference the pointer and assign something to it 
    return nil // or an error here 
} 

i jeśli nie było żadnego problemu, zwróci błąd. Teraz można powiedzieć

type Getter interface { 
    Get(int) error 
} 

i tak każdy typ, który określa Get(id)error można zdefiniować. Można wtedy użyć go w następujący sposób:

u := new(User) 
if err := u.Get(id); err != nil { 
    // problem getting user 
} 
// everything is cool. 
11

Golang nie obsługuje konstruktorów.

Zamiast tego należy użyć funkcji fabrycznych (Effective Go reference). Konwencja jest użycie New prefix:

func NewUser(id int) *User { 
    // Returns new User instance 
} 

Różnica między konstruktora i funkcji fabryczne to, że funkcja fabryka nie jest „przypisane” do User struktury. Jest to normalna funkcja, która zwraca User, podczas gdy konstruktor podobny do Java/C++ jest metodą, która modyfikuje nowo utworzony obiekt User w miejscu.

Powiązane problemy