2017-04-08 18 views
0

我明白這個問題,根據回答here,然而,我真的可以使用幫助或更詳細的代碼解釋如何克服它。克服進口週期不允許在Go

我的情況是這樣的:我曾經有模型和控制器分離,並在我的模型包我有包含的所有模型功能的接口datastore.go文件:

package models 

type DSDatabase interface { 
    CreateUser(ctx context.Context, username string, password []byte) (*datastore.Key, error) 
    // More model functions 
} 

type datastoreDB struct { 
    client *datastore.Client 
} 

var (
    DB DSDatabase 
    _ DSDatabase = &datastoreDB{} 
) 

func init() { 
    // init datastore 
} 

這是所有罰款因爲模型功能也位於模型包中,所以我在控制器包中的功能可以自由調用models.DB.CreateUser(ctx, "username", []byte("password"))

現在,我決定將所有上述代碼移至datastore包,而CreateUser的型號位於user包中。換句話說,package user現在包含控制器和模型功能,控制器相關功能依賴於datastore包,而DSDatabase接口依賴於user模型功能。

我真的很想知道如何克服導入週期,同時保持DSDatastore界面與其他所有軟件包(如homeuser)分離。


的情況下,上述的不夠清晰,上面的代碼已更改爲:

package datastore 

import (
    "github.com/username/projectname/user" 
) 

type DSDatabase interface { 
    user.CreateUser(ctx context.Context, username string, passwoUserRegister(ctx context.Context, username string, password []byte) (*datastore.Key, error) 
} 

... 

,而在我的user包我有這個控制器中的相關文件:

和另一個型號相關文件我有:

package user 

import (
    "github.com/username/projectname/datastore" 
) 

func (db *datastore.datastoreDB) CreateUser(ctx context.Context, username string) (*User, error) { 
    key := datastore.NameKey("User", username, nil) 
    var user User 
    err := db.client.Get(ctx, key, &user) 
    if err != nil { 
     return nil, err 
    } 
    return &user, nil 
} 

其中在進口週期過程的結果,我可悲的是無法弄清楚如何首先克服..

+1

你似乎在尋找技術解決方案,但你真的需要更好地界定哪些軟件包使用該。用術語來說,感覺就好像數據存儲是最低級別的,並且不會了解其他軟件包。但我無法真正瞭解您的業務邏輯。另外,在用戶包中有一個datastoreDB接收器感覺很奇怪。也許這種方法應該在數據存儲包中?也許代碼應該只在同一個包中?如果你看看現實生活中的項目,他們在同一個軟件包中有大量的文件。 – alexbt

+0

如果數據存儲和用戶都需要對方,那麼他們根本不能分開包。爲什麼他們首先在不同的包裝中? – JimB

+0

@alexbt在我使用MVC結構之前,我喜歡將控制器和模型放在一起的想法[按照我早期的問題推薦](https://stackoverflow.com/questions/43295691/identical-package-names-in-不同的文件夾爲同一項目)..datastore.go文件還包含配置,以創建一個單一的數據存儲客戶端,我可以使用datastoreDB接收器訪問..但它聽起來像我需要回去和'用戶模型函數和用戶控制器函數來分離包? – fisker

回答

1

第一件事,你不能定義一個方法,在pacakge一個,在聲明的類型包B

所以這...

package user 

import (
    "github.com/username/projectname/datastore" 
) 

func (db *datastore.datastoreDB) CreateUser(ctx context.Context, username string) (*User, error) { 
    key := datastore.NameKey("User", username, nil) 
    var user User 
    err := db.client.Get(ctx, key, &user) 
    if err != nil { 
     return nil, err 
    } 
    return &user, nil 
} 

...甚至不應該編譯。

這這裏...

package datastore 

import (
    "github.com/username/projectname/user" 
) 

type DSDatabase interface { 
    user.CreateUser(ctx context.Context, username string, passwoUserRegister(ctx context.Context, username string, password []byte) (*datastore.Key, error) 
} 

...這也是無效的Go代碼。


至於你的問題......有一兩件事你可以做的是定義user包裝內的Datastore接口並有實現生活在另一個包,這很好地借自己因爲當你需要一個不同的實現方式接口。如果你這樣做,你的user包不需要知道關於datastore包,datastore包仍然需要知道關於user包,但這是一個好的。

一個例子:

package user 

import (
    "context" 
) 

type DSDatabase interface { 
    CreateUser(ctx context.Context, username string, password []byte) (*User, error) 
    // ... 
} 

// This can be set by the package that implements the interface 
// or by any other package that imports the user package and 
// a package that defines an implementation of the interface. 
var DB DSDatabase 

type User struct { 
    // ... 
} 

func CreateUserPOST(w http.ResponseWriter, r *http.Request) { 
    // get formdata and such 
    DB.CreateUser(ctx, "username", []byte("password")) 
} 

包用接口的實現:

package datastore 

import (
    "context" 
    "github.com/username/projectname/user" 
) 

// DB implements the user.DSDatabase interface. 
type DB struct { /* ... */ } 

func (db *DB) CreateUser(ctx context.Context, username string) (*user.User, error) { 
    key := datastore.NameKey("User", username, nil) 
    var user user.User 
    err := db.client.Get(ctx, key, &user) 
    if err != nil { 
     return nil, err 
    } 
    return &user, nil 
} 

func init() { 
    // make sure to initialize the user.DB variable that 
    // is accessed by the CreateUserPOST func or else you'll 
    // get nil reference panic. 
    user.DB = &DB{} 
} 
+0

這太棒了,非常感謝。但是我想這意味着無法定義用戶包內的CreateUser函數?放棄'models'和'controllers'包結構的主要原因是將與用戶相關的所有函數放入用戶包中,但是似乎這個解決方案仍然會將所有模型函數放入'datastore'包中?我非常喜歡在'user'包中定義'DSDatabase'接口的想法,但是甚至可能不需要導入'datastore'包? – fisker

+0

您可以很好地在用戶包中具有CreateUser函數,但是然後讓DSDatabase接口看起來毫無意義。你需要什麼? – mkopriva

+0

但是,如果我理解正確,通過將CreateUser函數放在'user'包中,那麼您需要導入'datastore'包(否則最終會創建多個數據存儲客戶端),導致導入循環錯誤?我正在研究一個已經很大的web應用程序,並且我最終用特定的前綴命名了我的函數,因爲所有的文件都位於'controllers'和'models'包中,所以我正在尋找一種方法來分割它。 – fisker