doucuo8618 2019-07-08 18:03
浏览 35

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

I'm just discovering Go. When I started looking at it last week, I found out GOPATH and how Go apparently is very opinionated about what directories you store your code in. So I cursed Google's name and decided Go wasn't for me, then recently heard about Go modules and how apparently they resolve this very issue.

The trouble is that information online on how to structure a module-based Go project appears to be very scarce. I'm having trouble figuring out how to lay out my code and what to call the packages in order to get imports working. I've tried various things and looked at examples but no matter what I do, I get "unknown import path" errors.

Basically I want to have a directory with, say, main.go and library.go, maybe with library.go in a subdirectory. I want to be able to write import library or something similar in main.go and be able to access members of library.go. I also want to be able to run the code by typing go run main.go. Is this achievable?

  • 写回答

1条回答 默认 最新

  • dqls67891 2019-07-08 19:46
    关注

    It is confusing and the documentation assumes a level of familiarity with Golang. I've been trying to understand Modules recently. I hope the following helps.

    Best wishes learning Golang.

    The previous|current way without Modules:

    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}
    

    Then create ${WORKDIR}/go/src/foo/bar/library.go:

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

    Then create ${WORKDIR}/go/src/foo/main.go:

    package main
    
    import (
        "fmt"
        "foo/bar"
    )
    
    func main() {
        fmt.Printf("%s", bar.Something())
    }
    

    You'll have a structure like this:

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

    Then you may run this either of the following ways:

    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!
    

    The new (!) way with Modules:

    Assuming you've done the above!

    You don't need to do this step but this is the new best practice. We're moving our sources outside of ${GOPATH}. ${GOPATH} is still used to store our versioned packages. NB In this trivial example, we're not using external packages so ${GOPATH} remains empty.

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

    You should a structure like this:

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

    NB Our sources are now outside of ${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!
    

    For Completeness

    To show the difference with external packages:

    No Modules pulls the latest version of the package into ${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
    

    Versus using Modules, pulls a specific version (or versions) of the package into ${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
    
    

    Notes

    • Our file names are somewhat arbitrary. You said library.go so I've used that and conventionally, files are named after their content.
    • Our directory names are important. Go uses directory names to help find packages. So, even though library.go could have been called freddie.go or something.go, it's important that it be package bar and in a directory called bar.
    • An exception to these rules is that main.go is conventionally where func main() {...} is defined and func main() {...} must be in a package called main. So, even though the directory is called foo, because we want a main function, we name the file main.go and it must be package main.
    • In package bar, it's important that Something be initially capitalized (S). This exports the function from the bar package so that it may be used by other packages. If the function's name were lowercase (something), the function is only available to other functions within the bar package.
    评论

报告相同问题?