我对Golang很新,并试图使一个简单的REST API应用程序工作.
最初,一切都很好,因为我将所有代码放在main包下的同一目录中.
但是,现在我处于一个需要开始将代码重构为子目录和包的阶段.不幸的是,我无法成功编译应用程序.
我GOPATH的设置为:~/.workspace
当前的应用程序位于:~/.workspace/src/gitlab.com/myapp/api-auth
这就是我目前的代码组织:
这是我的 main.go
package main
import (
"net/http"
"os"
"strings"
"github.com/gorilla/context"
"github.com/justinas/alice"
"gopkg.in/mgo.v2"
"gitlab.com/myapp/api-auth/middlewares"
)
func main() {
privateKey := []byte(strings.Replace(os.Getenv("JWT_KEY"), "\\n", "\n", -1))
conn, err := mgo.Dial(os.Getenv("MONGO_CONN"))
if err != nil {
panic(err)
}
defer conn.Close()
conn.SetMode(mgo.Monotonic, true)
ctx := appContext{
conn.DB(os.Getenv("MONGO_DB")),
privateKey,
}
err = ctx.db.C("users").EnsureIndex(mgo.Index{
Key: []string{"username"},
Unique: true,
Background: true,
Sparse: false,
})
if err != nil {
panic(err)
}
commonHandlers := alice.New(LoggingHandler, context.ClearHandler, RecoveryHandler, AcceptHandler, ContentTypeHandler)
router := NewRouter()
router.Post("/users", commonHandlers.Append(BodyParserHandler(UserResource{})).ThenFunc(ctx.userCreationHandler))
router.Post("/sessions", commonHandlers.Append(BodyParserHandler(UserResource{})).ThenFunc(ctx.sessionCreationHandler))
http.ListenAndServe(":8080", router)
}
type appContext struct {
db *mgo.Database
privateKey []byte
}
Run Code Online (Sandbox Code Playgroud)
这是中间件之一(中间件的accept.go其余部分构造类似)
package middlewares
import "net/http"
// AcceptHandler ensures proper accept headers in requests
func AcceptHandler(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Accept") != "application/vnd.api+json" {
writeError(w, errNotAcceptable)
return
}
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
Run Code Online (Sandbox Code Playgroud)
这是我go build从应用程序的根目录运行时出现的错误.
# gitlab.com/utiliti.es/api-auth
./main.go:11: imported and not used: "gitlab.com/myapp/api-auth/middlewares"
./main.go:42: undefined: LoggingHandler
./main.go:42: undefined: RecoveryHandler
./main.go:42: undefined: AcceptHandler
./main.go:42: undefined: ContentTypeHandler
./main.go:45: undefined: BodyParserHandler
./main.go:46: undefined: BodyParserHandler
Run Code Online (Sandbox Code Playgroud)
pet*_*rSO 15
限定标识符是使用包名称前缀限定的标识符.包名称和标识符都不能为空.
Run Code Online (Sandbox Code Playgroud)QualifiedIdent = PackageName "." identifier .限定标识符访问必须导入的不同包中的标识符.必须在该包的包块中导出和声明标识符.
Run Code Online (Sandbox Code Playgroud)math.Sin // denotes the Sin function in package math导入声明声明包含声明的源文件取决于导入的包的功能(§程序初始化和执行),并允许访问该包的导出标识符.导入命名用于访问的标识符(PackageName)和指定要导入的包的ImportPath.
Run Code Online (Sandbox Code Playgroud)ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) . ImportSpec = [ "." | PackageName ] ImportPath . ImportPath = string_lit .PackageName用于限定标识符,以访问导入源文件中包的导出标识符.它在文件块中声明.如果省略PackageName,则默认为导入包的package子句中指定的标识符.如果出现显式句点(.)而不是名称,则在该包的包块中声明的所有包的导出标识符将在导入源文件的文件块中声明,并且必须在没有限定符的情况下访问.
ImportPath的解释依赖于实现,但它通常是已编译包的完整文件名的子字符串,并且可能与已安装包的存储库相关.
实施限制:编译器可能限制ImportPaths使用属于统一的l只有字符非空字符串,M,N,P和S大类(图形字符没有空格),也可以排除字符"#$%&! '()*,:; <=>?[] ^`{|}和Unicode替换字符U + FFFD.
假设我们编译了一个包含package子句包math的包,它导出函数Sin,并将编译后的包安装在由"lib/math"标识的文件中.此表说明了在各种类型的导入声明后导入包的文件中如何访问Sin.
Run Code Online (Sandbox Code Playgroud)Import declaration Local name of Sin import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin导入声明声明导入和导入的包之间的依赖关系.软件包直接或间接导入自身或直接导入软件包而不引用任何导出的标识符是非法的.要仅为其副作用(初始化)导入包,请使用空白标识符作为显式包名:
Run Code Online (Sandbox Code Playgroud)import _ "lib/math"
错误
./main.go:11: imported and not used: "gitlab.com/myapp/api-auth/middlewares"
Run Code Online (Sandbox Code Playgroud)
说你没有使用middlewares包装main,这是真的.
错误
./main.go:42: undefined: AcceptHandler
Run Code Online (Sandbox Code Playgroud)
说你没有AcceptHandler在包中定义main,这是真的.
"限定标识符是使用包名称前缀限定的标识符.限定标识符访问必须导入的不同包中的标识符."
例如,在包中main,使用限定标识符middlewares.AcceptHandler,该标识符是导入的使用"gitlab.com/myapp/api-auth/middlewares".