2013-09-07 9 views
29

Ich suche Rat für die beste Möglichkeit, die folgende Struktur zu bereinigen. Ich weiß, Go hat keine statischen Methoden und es ist in der Regel better to encapsulate functionality in a separate package. Meine Strukturtypen referenzieren sich gegenseitig und können daher aufgrund von Ringimporten nicht in separaten Paketen deklariert werden.Go: "Static" -Methodedesign

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 
} 

Aber wenn ich einen Benutzer oder eine Zahlung zu laden, ich warf ich den Hörer einfach weg:

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

Ich konnte die Funktionen selbst Namespace, der mich als unrein trifft:

Ich würde wirklich gerne nur .Get oder ähnliche auf der Struktur aufrufen können, ohne den Namen der Struktur in der Funktion selbst zu schreiben. Was ist der idiomatische Weg, dies zu tun?

Antwort

23

GetUser() und GetPayment() Streik mich als völlig klar und idiomatisch. Ich bin mir nicht sicher, was du an ihnen unrein findest.

Aufruf .Get() auf einer Struktur zurückgeben ein anderes Struct ist die Sache, die mich als sehr seltsam, unklar und unidiomatisch.

Ich denke, dies könnte ein Fall von nur bleiben mit dem Idiom und Vertrauen, dass Sie sich daran gewöhnen werden.

+2

Ja, ich finde '.Get()' auf einer Struktur, die ich noch unrein wegwerfen. Für mich ist 'User.Get()' am saubersten; Wenn 'GetUser' die engste Annäherung ist, die ich bekommen kann, nehme ich es. – ash

+1

@ash Ja, ich glaube, es ist der nächste, den Sie bekommen können, und der idiomatische Weg, es zu tun. –

+0

Sie können mit GetUser und GetPayment keine Frameworks und Bibliotheken erstellen – rocketspacer

10

mit einer Get Funktion ist völlig in Ordnung; es ist nicht unidiomatic in irgendeiner Weise.

func (u *User) Get(id int) *User macht keinen Sinn, obwohl es func (u *User) Get(id int) error sein sollte. Die einzige Sache, die Sie verpassen, ist, dass Sie einen Methodenempfänger für einen Zeiger definieren können, und dann den Zeiger innerhalb dieser Methode dereferenzieren, um zu überschreiben, worauf er hinweist.

So:

// 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 
} 

und wenn es irgendein Problem war, einen Fehler zurück. Jetzt können Sie sagen

type Getter interface { 
    Get(int) error 
} 

und so jede Art, die Get(id)error definiert definiert werden. Sie würden es dann so verwenden:

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

Golang unterstützt keine Konstruktoren.

Verwenden Sie stattdessen die Werksfunktionen (Effective Go reference). Die Konvention ist New Präfix zu verwenden:

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

Der Unterschied zwischen Konstruktor und Fabrik Funktion ist die Fabrik-Funktion ist nicht „gebunden“ an die User Struct. Es ist eine normale Funktion, die zufällig User zurückgibt, während der Java/C++ - ähnliche Konstruktor eine Methode ist, die das neu erstellte User Objekt an Ort und Stelle ändert.