英文:
How to properly import a package from sub-directory in Golang?
问题
我对Golang还不太熟悉,但我可以帮你翻译一下你的代码和错误信息。以下是翻译的结果:
我对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
}
这是其中一个中间件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)
}
这是当我在应用程序的根目录运行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
希望这可以帮助到你。如果你有任何其他问题,请随时问我。
英文:
I am pretty new to Golang and trying to make a simple REST api app work.
Initially, everything was all fine since I had all code in the same directory under the main
package.
But, now I am at a stage where I need to start refactoring code into sub-directories and packages. Unfortunately, I have not been able to compile the app successfully.
My GOPATH
is set to: ~/.workspace
The current app is at: ~/.workspace/src/gitlab.com/myapp/api-auth
This is how my current code organization is:
Here is my 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
}
Here is one of the middleware accept.go
(Rest of the middleware are constructed similarly)
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)
}
This is the error I get when I run go build
from root of my app.
# 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
答案1
得分: 23
《Go编程语言规范》
限定标识符
限定标识符是带有包名前缀的标识符。包名和标识符都不能是空白的。
QualifiedIdent = PackageName "." identifier
限定标识符用于访问不同包中的标识符,该包必须被导入。该标识符必须在该包的包块中被导出和声明。
math.Sin // 表示math包中的Sin函数
导入声明
导入声明表示包含该声明的源文件依赖于导入包的功能(§程序初始化和执行),并且可以访问该包的导出标识符。导入声明命名一个用于访问的标识符(PackageName),并指定要导入的包的ImportPath。
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
PackageName用于限定标识符,以便在导入源文件中访问该包的导出标识符。它在文件块中声明。如果省略PackageName,则默认为导入包的包子句中指定的标识符。如果出现一个显式的句点(.)而不是名称,则该包的所有导出标识符将在导入源文件的文件块中声明,并且必须在没有限定符的情况下访问。
ImportPath的解释依赖于实现,但通常是编译包的完整文件名的子字符串,并且可以相对于已安装包的存储库。
实现限制:编译器可以限制ImportPaths为非空字符串,仅使用属于Unicode的L、M、N、P和S通用类别(没有空格的图形字符),并且还可以排除字符!"#$%&'()*,:;<=>?[]^`{|}和Unicode替换字符U+FFFD。
假设我们已经编译了一个包,其中包子句为package math,导出了函数Sin,并且将编译的包安装在由"lib/math"标识的文件中。此表说明了在导入各种类型的导入声明之后,如何在导入该包的文件中访问Sin。
导入声明 Sin的本地名称
import "lib/math" math.Sin
import m "lib/math" m.Sin
import . "lib/math" Sin
导入声明声明了导入包之间的依赖关系。一个包不能直接或间接地导入自身,也不能直接导入一个包而不引用其任何导出标识符。要仅为了其副作用(初始化)导入一个包,请使用空白标识符作为显式包名。
import _ "lib/math"
错误
./main.go:11: imported and not used: "gitlab.com/myapp/api-auth/middlewares"
表示在包main
中没有使用middlewares
包,这是正确的。
错误
./main.go:42: undefined: AcceptHandler
表示在包main
中没有定义AcceptHandler
,这是正确的。
“限定标识符是带有包名前缀的标识符。限定标识符用于访问不同包中的标识符,该包必须被导入。”
例如,在包main
中,使用限定标识符middlewares.AcceptHandler
,这是对导入"gitlab.com/myapp/api-auth/middlewares"
的使用。
英文:
> The Go Programming Language Specification
>
> Qualified identifiers
>
> A qualified identifier is an identifier qualified with a package name
> prefix. Both the package name and the identifier must not be blank.
>
> QualifiedIdent = PackageName "." identifier .
>
> A qualified identifier accesses an identifier in a different package,
> which must be imported. The identifier must be exported and declared
> in the package block of that package.
>
> math.Sin // denotes the Sin function in package math
>
> Import declarations
>
> An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program
> initialization and execution) and enables access to exported
> identifiers of that package. The import names an identifier
> (PackageName) to be used for access and an ImportPath that specifies
> the package to be imported.
>
> ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
> ImportSpec = [ "." | PackageName ] ImportPath .
> ImportPath = string_lit .
>
> The PackageName is used in qualified identifiers to access exported identifiers of the package within the importing source file.
> It is declared in the file block. If the PackageName is omitted, it
> defaults to the identifier specified in the package clause of the
> imported package. If an explicit period (.) appears instead of a name,
> all the package's exported identifiers declared in that package's
> package block will be declared in the importing source file's file
> block and must be accessed without a qualifier.
>
> The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled
> package and may be relative to a repository of installed packages.
>
> Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to Unicode's L, M,
> N, P, and S general categories (the Graphic characters without spaces)
> and may also exclude the characters !"#$%&'()*,:;<=>?[]^`{|} and the
> Unicode replacement character U+FFFD.
>
> Assume we have compiled a package containing the package clause package math, which exports function Sin, and installed the compiled
> package in the file identified by "lib/math". This table illustrates
> how Sin is accessed in files that import the package after the various
> types of import declaration.
>
> Import declaration Local name of Sin
>
> import "lib/math" math.Sin
> import m "lib/math" m.Sin
> import . "lib/math" Sin
>
> An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import
> itself, directly or indirectly, or to directly import a package
> without referring to any of its exported identifiers. To import a
> package solely for its side-effects (initialization), use the blank
> identifier as explicit package name:
>
> import _ "lib/math"
The error
./main.go:11: imported and not used: "gitlab.com/myapp/api-auth/middlewares"
says that you have no uses of package middlewares
in package main
, which is true.
The error
./main.go:42: undefined: AcceptHandler
says that you haven't defined AcceptHandler
in package main
, which is true.
"A qualified identifier is an identifier qualified with a package name prefix. A qualified identifier accesses an identifier in a different package, which must be imported."
For example, in package main
, use the qualified identifier middlewares.AcceptHandler
, which is a use of import "gitlab.com/myapp/api-auth/middlewares"
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论