How to properly import a package from sub-directory in Golang?

huangapple go评论67阅读模式
英文:

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

这是我当前的代码组织方式:

How to properly import a package from sub-directory in Golang?

这是我的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:

How to properly import a package from sub-directory in Golang?

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: &quot;gitlab.com/myapp/api-auth/middlewares&quot;

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 &quot;gitlab.com/myapp/api-auth/middlewares&quot;.

huangapple
  • 本文由 发表于 2016年2月7日 01:09:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/35243865.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定