LoginSignup
34
27

More than 5 years have passed since last update.

【Golang】独自パッケージのインポート

Last updated at Posted at 2019-05-11

概要

次のようなディレクトリ構造で、Goによるコーディングを行なっていました。

その際に独自パッケージのインポートでちょっと詰まってしまったので、その際の解決方法を残します。

前提

ディレクトリ構造は次のようにした。

~/
  code/

    src/

      ruby/
      swift/
      kotlin/
      javascript/
      ...
      golang/

        repo1/
        repo2/
        ...
        repo10/

          main.go             # エントリーポイントのファイル
          sub.go              # mainパッケージ内の関数群
          readme.md
          package1/           # 自作パッケージのディレクトリ
            package1.go 
          package2/           # 自作パッケージのディレクトリ
            package2.go
          ...

各ファイルは次のようにした。

main.go

package main

func main() {
  doSomething()
}
sub.go

package main

// 最初に書いた呼び出し方。
// これでは呼び出せない。
import "package1"

func doSomething() {
  // 独自パッケージ内の関数を呼び出す
  package1.OriginalPackageFunction()
}
package1.go

package package1

func OriginalPackageFunction() {
  // do something.
}

GOPATHは次のように設定した。

$GOPATH = "$HOME/code"

エラー

これで go run mai.go sub.go を実行すると、次のようにエラーが出た。

sub.go:3:2: cannot find package "package1" in any of:
        /PATH/OF/YOUR/GOROOT/src/package1 (from $GOROOT)
        /PATH/OF/YOUR/GOPATH/src/package1 (from $GOPATH)

この結果から、Golangでパッケージをimportすると、次のディレクトリを探すとわかった。

  • $GOROOT/src 配下のパッケージ名のディレクトリの中
  • $GOPATH/src 配下のパッケージ名のディレクトリの中

解決のポイント

Golangでのパッケージインポートは、Gopherたちがどのようにパッケージのやり取りをしているかに関係している。

Golang では、外部パッケージの取得に go getコマンドを使用する。

例えば、githubに公開されているgo-kit/kitというパッケージを使いたい場合は、

go get github.com/go-kit/kit

というコマンドでパッケージの取得を行える。

具体的には、$GOAPTH/src 内に、指定したレポジトリをクローンする。

つまり、go get github.com/go-kit/kitを実行すると、次のようなディレクトリ構造になる。

~/
  code/

    src/
      ruby/
      swift/
      kotlin/
      javascript/
      ...
+     github.com/             # ここにクローンされる
+       go-kit/
+         kit/
+           ...

      golang/

        repo1/
        repo2/
        ...
        repo10/

          main.go             # エントリーポイントのファイル
          sub.go              # mainパッケージ内の関数群
          readme.md
          package1/           # 自作パッケージのディレクトリ
            package1.go
          package2/           # 自作パッケージのディレクトリ
            package2.go
          ...

[参考] Golang のwikiより引用

Repository integration and creating "go gettable" projects


When fetching a package the go tool looks at the package's import path to discover a URL. For instance, if you attempt to

go get github.com/go-kit/kit

the go tool will get the source from the project hosted at https://github.com/go-kit/kit/. It will clone the repository to

$GOPATH/src/github.com/go-kit/kit

As a result, if (from your repository project) you import a package that is in the same repository, you need to use its "full" import path - the place "go get" puts it. In this example, if something else wants to import the "kit" package, it should import "github.com/go-kit/kit" rather than "kit".

解決策

もっとも良い方法は、$GOPATH/src 以下が、自身のリモートレポジトリのURLと同じになるように作業ディレクトリを変更すること。

例えば、githubでレポジトリを管理しているなら、github.com/username/reponame となるので、
今回の場合だと、

~/
  code/

    src/
      ruby/
      swift/
      kotlin/
      javascript/
      ...
      golang/
        src/
+         github.com/
+           username/
              repo1/
              repo2/
              ...
              repo10/
                main.go
                sub.go
                readme.md
                package1/
                  package1.go
                package2/
                  package2.go
                ...

とした上で、

$GOPATH="$HOME/code/src/golang/"

と貼り直す。

そして、インポート文を書き直す。

// sub.go

package main

// これで呼び出せる。
import "github.com/username/repo10/package1"

func doSomething() {
  // 独自パッケージ内の関数を呼び出す
  package1.OriginalPackageFunction()
}

補足 1

他の言語では、外部モジュールを相対パスで指定してインポートすることができます。

Golangでも、相対パスでのimportも可能です。

import "./package1"

この方法は推奨されていません。

特に、go testなどで相対パスによるimportを行うと、

local import "./package1" in non-local package

となります。

補足 2

一つのpackageディレクトリにまとめることもできるようです。

~/
  code/

    src/
      ruby/
      swift/
      kotlin/
      javascript/
      ...
      golang/
        src/
          github.com/
            username/
              repo1/
              repo2/
              ...
              repo10/
                main.go
                sub.go
                readme.md
+               original_packages/
+                 package1.go
+                 package2.go
+                 ...

ただし、この場合、import文が少し変わります。

// sub.go

package main

// パスの前にパッケージ名を記述する。
import package1 "github.com/username/repo10/original_package"

func doSomething() {
  // 独自パッケージ内の関数を呼び出す
  package1.OriginalPackageFunction()
}
34
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
27