いろいろ備忘録日記

主に .NET とか Java とか Python絡みのメモを公開しています。最近Go言語勉強中。

go fmt をプロジェクト配下の全ファイルに対して実行したい

概要

Go言語勉強中です。これも忘れないようメモ。基本的なことばかりですが・・w

go fmt をプロジェクト配下の全ファイルに一発で適用したいって話です。

勉強になったのは、以下の内容。

stackoverflow.com

ソース構成

以下のようになってるとします。

$ tree
.
├── go.mod
├── main.go
└── pkg
    └── lib
        └── lib.go

go fmt をそのまま実行する

ソースツリーのトップディレクトリに今いるとして、go fmt ってすると

$ go fmt
main.go

って感じで、実行したディレクトリの go ファイルだけがフォーマットされます。

サブディレクトリも含めて全部 go fmt したい

... という記法を使うと、それ以下のファイルを対象にできます。

$ go fmt ./...
pkg/lib/lib.go
main.go

それか、パッケージ指定して ... をつける

$ go fmt github.com/devlights/go-pkg-dir/...
main.go
pkg/lib/lib.go 

なお、今いるディレクトリのパッケージ表記は go list ってやれば取れるので

$ go fmt $(go list)/...
main.go
pkg/lib/lib.go

でもオッケイ。

gofmt コマンド使っても良い

go fmt のヘルプ見ると分かりますが、go fmt は、内部で gofmt を呼び出しています。

$ go help fmt
usage: go fmt [-n] [-x] [packages]

Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified.

For more about gofmt, see 'go doc cmd/gofmt'.
For more about specifying packages, see 'go help packages'.

The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.

To run gofmt with specific options, run gofmt itself.

gofmt コマンドの方は、再帰でファイルを見てくれます。さらにこっちの方が多機能。

ってことで、gofmt を使うと以下で同じ結果となります。

$ gofmt -l -w .
main.go
pkg/lib/lib.go

どうせなら、コードのシンプル化のオプションもあるのでつけてしまって

$ gofmt -l -s -w .
main.go
pkg/lib/lib.go

でもいいですね。

-s を付与したときの挙動は、以下に記載されています。

golang.org


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com

go build のちょっとしたクセ (go buildは指定されたディレクトリをビルド対象にする)

概要

元ネタは以下。

forum.golangbridge.org

上のページの内容は、mainパッケージのものを配置するために main ってディレクトリ作って

その中に、main パッケージのものを入れました。その後で、いつもどおりにトップディレクトリで

go build

ってやったら、

$ go build
can't load package: package github.com/devlights/go-main-pkg-dir: unknown import path "github.com/devlights/go-main-pkg-dir": cannot find module providing package github.com/devlights/go-main-pkg-dir

ってエラー出てビルドできないんだけど何で?って内容です。

なんでメモ残そうかと思ったかというと、Go言語勉強し始めたときに自分でも、この状態になってしまったのでw

今でもたまに go build したときに、同じエラーメッセージ出たりしてます。。

Go言語では一つのディレクトリの中には一つのパッケージしか存在できない

Go言語、最初に勉強し始めたときに作るサンプルってだいたい以下のような形してると思います。

$ tree
.
├── go.mod
├── lib.go
└── main.go

パッケージ用のディレクトリなんて無しで、直下に main.go 置いているパターン。

main.golib.go ともに main パッケージに属している。

この場合

go build

って打つと、素直にビルド成功。

で、ちょっと言語の勉強しだすと以下のような言語仕様を見かける。

Goでは、一つのディレクトリの中に一つのパッケージしか存在できない

なるほどってなって、んじゃ main パッケージのものは main の下に入れようってなります(私はなりましたw

んで、構成がこうなる

$ tree
.
├── go.mod
└── main
    ├── lib.go
    └── main.go

この状態になって、さっきと同じようにトップディレクトリで go build ってやると件のエラーが出ます。

今は理由もわかるんですが、勉強し始めの頃は意味が分かっていませんでした。

誤解の元は、go build ってやると、再帰で実行したディレクトリから下も含めて全部見てくれていると思ってたせい。

だって、以下のような構成の場合

$ tree
.
├── go.mod
├── main.go
└── pkg
    └── lib
        └── lib.go

go build って同じようにやっても、ちゃんとビルド出来るのですからw

サブパッケージ扱いの lib.go は自動的にビルド対象に入る。

普段、dotnet とかやってるのもあって、エントリーポイントを持つファイルとかは勝手に探してくれると勘違いしてました.

上のサイトでもちゃんと説明してくださってます。

The reason is that Go packages must all be in the same folder. When you run go build from /root/folder/, go build looks for .go files in that folder to build a package. go build does not traverse the directory structure from the current directory and build subpackages.

ってことで、正しくはこうですね。

$ cd main
$ go build

それか、

$ go build -o xxx ./main

それか、パッケージ直指定

$ go build -o xxx name/of/package/main

そもそも main ってディレクトリ掘って、配置しておくってのが、今考えるとあまりやらないですが。

(cmdディレクトリ掘って、下にアプリケーション名を掘って、その下に main.go 置くパターンが最近個人的に多いです)


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com

go.mod ファイルのGoランタイムのバージョン変更の仕方 (go mod edit)

概要

忘れないうちにメモメモ。

Go Modules を使って、モジュール管理するのが今後のやり方になると思いますが

一旦、作成した go.mod ファイルの

go 1.12

とか記載されるランタイムのバージョンってどうやって更新するのかなってなって、ちょっと調べたのでメモ。

環境

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.14.5
$ go version
go version go1.12.8 darwin/amd64

go.mod ファイルって手でいじったら駄目な感じがする・・・

go.mod ファイル自体が、

go mod init name/of/package

って感じで生成して、それ以降も自動的に調整されていくので

手でいじったら駄目な感じがしてました。

ちゃんと edit ってサブコマンドがあった

わからんかったら、素直にヘルプ見るですね

 go mod
Go mod provides access to operations on modules.

Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.

Usage:

    go mod <command> [arguments]

The commands are:

    download    download modules to local cache
    edit        edit go.mod from tools or scripts
    graph       print module requirement graph
    init        initialize new module in current directory
    tidy        add missing and remove unused modules
    vendor      make vendored copy of dependencies
    verify      verify dependencies have expected content
    why         explain why packages or modules are needed

Use "go help mod <command>" for more information about a command.

ちゃんと edit ってサブコマンドありました。これ使えばいいのだろうと予想。

$ go mod edit
go mod edit: no flags specified (see 'go help mod edit').

フラグが指定されていないってメッセージでた。。指定が足りていないみたい。なので、書かれているヘルプみる。

$ go help mod edit
usage: go mod edit [editing flags] [go.mod]

Edit provides a command-line interface for editing go.mod,
for use primarily by tools or scripts. It reads only go.mod;
it does not look up information about the modules involved.
By default, edit reads and writes the go.mod file of the main module,
but a different target file can be specified after the editing flags.

・・省略・・・

めっちゃ大量にヘルプでた。。もうちょい絞りたいな・・・

$ go help mod edit | grep version
The -require=path@version and -droprequire=path flags
add and drop a requirement on the given module path and version.
Users should prefer 'go get path@version' or 'go get path@none',
The -exclude=path@version and -dropexclude=path@version flags
add and drop an exclusion for the given module path and version.
Note that -exclude=path@version is a no-op if that exclusion already exists.
add and drop a replacement of the given module path and version pair.
If the @v in old@v is omitted, the replacement applies to all versions
The -go=version flag sets the expected Go language version.

お、一番下に -go=version ってフラグを指定したらセットされるって記載がある。

てことで、試してみます。(下にでてくる try-golang ってのは自分用の勉強リポジトリです)

$ go version
go version go1.12.8 darwin/amd64


# 今の go.mod (go 1.12ってなってる)
$ cat go.mod
module github.com/devlights/try-golang

go 1.12

require github.com/deckarep/golang-set v1.7.1

# 変更してみる (1.12 --> 1.11)
$ go mod edit -go=1.11

# 差分見てみる
$ git diff
diff --git a/go.mod b/go.mod
index 5d2648c..7891f6d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,5 @@
 module github.com/devlights/try-golang

-go 1.12
+go 1.11

 require github.com/deckarep/golang-set v1.7.1

# 元に戻す
$ git checkout -- go.mod

ちゃんと変わりますね。これで次のメジャーバージョンアップとかしたときに

go mod edit -go=1.13

とかやったら、ちゃんと変更できそう。


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com