我应该如何构造Go模块,以便能够轻松运行它并导入内部软件包?

时间:2019-07-08 18:03:46

标签: go

我只是发现Go。当我上周开始查看它时,我发现了GOPATH以及Go显然对将代码存储在哪个目录中的态度很坚决。于是我诅咒Google的名字,并确定Go不适合我,然后最近听说了Go模块和他们显然如何解决了这个问题。

问题在于,有关如何构建基于模块的Go项目的在线信息非常匮乏。我在弄清楚如何布置我的代码以及如何调用软件包以使导入正常工作方面遇到困难。我已经尝试了各种方法并查看了示例,但是无论我做什么,都会出现“未知的导入路径”错误。

基本上,我希望有一个包含[]main.go的目录,也许还有一个子目录中的library.go。我希望能够在library.go中写import library或类似的东西,并能够访问main.go的成员。我还希望能够通过键入library.go来运行代码。这可以实现吗?

1 个答案:

答案 0 :(得分:1)

这令人困惑,并且文档假定您对Golang有所了解。我最近一直在尝试了解Modules。希望以下内容对您有所帮助。

最高兴学习Golang。

以前的|当前没有模块的方式:

WORKDIR=[[PATH-TO-YOUR-WORKING-DIRECTORY]]

mkdir -p ${WORKDIR}/go
export GOPATH=${WORKDIR}/go
export PATH=${GOPATH}/bin:${PATH}

mkdir -p {${WORKDIR}/go/src/foo, ${WORKDIR}/go/src/foo/bar}

然后创建${WORKDIR}/go/src/foo/bar/library.go

package bar

func Something() (string) {
    return "Hello Freddie"
}

然后创建${WORKDIR}/go/src/foo/main.go

package main

import (
    "fmt"
    "foo/bar"
)

func main() {
    fmt.Printf("%s", bar.Something())
}

您将拥有这样的结构:

.
└── go
    └── src
        └── foo
            ├── bar
            │   └── library.go
            └── main.go

然后您可以通过以下两种方式之一来运行它:

GO111MODULE=off go run ${WORKDIR}/go/src/main.go
Hello Freddie!

cd ${WORKDIR}/go/src/
GO111MODULE=off go run main.go
Hello Freddie!

GO111MODULE=off go run foo
Hello Freddie!

模块的新(!)方式:

假设您已完成上述操作!

您无需执行此步骤,但这是新的最佳实践。我们正在将我们的来源移至${GOPATH}之外。 ${GOPATH}仍用于存储我们的版本包。 NB 在这个简单的示例中,我们没有使用外部软件包,因此${GOPATH}仍然为空。

mv ${WORKDIR}/go/src/foo ${WORKDIR}
rm ${WORKDIR}/go/src

您应使用以下结构:

.
├── foo
│   ├── bar
│   │   └── library.go
│   └── main.go
└── go

NB 我们的消息来源现在不在${GOPATH}

之外
cd ${WORKDIR}/foo

GO111MODULE=on go mod init foo
more go.mod
module foo

go 1.12

GO111MODULE=on go run foo
Hello Freddie!

GO111MODULE=on go run main.go
Hello Freddie!

为了完整性

要显示与外部软件包的区别:

没有模块将软件包的最新版本放入${GOPATH}/src

GO111MODULE=off go get github.com/golang/glog

.
├── foo
│   ├── bar
│   │   └── library.go
│   ├── go.mod
│   ├── go.sum
│   └── main.go
└── go
    └── src
        └── github.com
            └── golang
                └── glog
                    ├── glog_file.go
                    ├── glog.go
                    ├── glog_test.go
                    ├── LICENSE
                    └── README

相对于使用模块,将软件包的特定版本(或多个版本)拉入${GOPATH}/pkg

GO111MODULE=on go get github.com/golang/glog

.
├── foo
│   ├── bar
│   │   └── library.go
│   ├── go.mod
│   ├── go.sum
│   └── main.go
└── go
    └── pkg
        ├── linux_amd64
        │   └── github.com
        │       └── golang
        │           └── glog.a
        └── mod
            ├── cache
            │   ├── download
            │   │   └── github.com
            │   │       └── golang
            │   │           └── glog
            └── github.com
                └── golang
                    └── glog@v0.0.0-20160126235308-23def4e6c14b
                        ├── glog_file.go
                        ├── glog.go
                        ├── glog_test.go
                        ├── LICENSE
                        └── README

注释

  • 我们的文件名有些随意。您说过library.go,所以我已经习惯了,按照惯例,文件是根据其内容命名的。
  • 我们的目录名称很重要。 Go使用目录名称来帮助查找软件包。因此,即使可以将library.go称为freddie.gosomething.go,也必须将package bar放在目录bar中。
  • 这些规则的一个例外是,main.go通常是在定义func main() {...}的地方,并且func main() {...}必须位于称为main的程序包中。因此,即使目录名为foo,由于我们想要一个main函数,我们仍将文件命名为main.go,并且文件的名称必须为package main
  • 在软件包bar中,重要的是Something首先要大写(S)。这将从bar包中导出函数,以便其他包可以使用它。如果函数名称为小写(something),则该函数仅可用于bar包中的其他函数。