Closed6

今更golang始める人の備忘録

吉村吉村

Me

  • JavaとかC#(.NET Coreじゃないほう)とかのエンタープライズフルスタックガッチガチ系アプリ屋。Web周りやっててフロントサーバーインフラある程度は行けるが、ある程度で止まっている上に古い。
  • Rails, Laravelあたりは軽く触ったことがあるが、触った程度でちゃんと仕事で触れたことはない。
  • フロントの知識はRollup.jsが出てきた辺りで止まっている。今やWebpackチャンク職人しなくていいってマジ?
  • 最近マネジメント周りに手を出さざるを得なくなってそっちの方ばかり手を出してたけど、プログラミングやりたい欲が噴出したので言語勉強に手を出し始めた。

Stance of scrap

  • 新しく言語を学ぶ、というのが久々なので、他の言語やるときにどういう手順でやったか思い出すための備忘録
  • あわよくば強いエンジニアに「こっちの方がいいですよ」という指摘もらえないかと期待している。
  • 「見てて有意義」は目指さない。あたふたしながらやる。半分くらい日記帳みたいなつもりでやる。

env

  • OS: Windows11 Pro 2022H2
  • Go Version: 1.19.1
  • Editor: VSCode + Go Plugin
吉村吉村

A Tour of Go

最初にやるといいらしいのでとりあえず手を出してみる。
日本語版があるので、変に自分で翻訳して正しい意味を取れないよりは翻訳されたものを素直に受け取る方が吉と判断。
Webエディタでやるよりローカルで触る方が変なショートカット暴発でイラッとしなくていいなと考え、日本語版で指示されたままにgo getで開始しようとする。

PS > go get github.com/atotto/go-tour-jp/gotour

go: go.mod file not found in current directory or any parent directory.
        'go get' is no longer supported outside a module.
        To build and install a command, use 'go install' with a version,
        like 'go install example.com/cmd@latest'
        For more information, see https://golang.org/doc/go-get-install-deprecation
        or run 'go help get' or 'go help install'.
PS > go install github.com/atotto/go-tour-jp/gotour

go: 'go install' requires a version when current directory is not in a module
        Try 'go install github.com/atotto/go-tour-jp/gotour@latest' to install the latest version
PS > go install github.com/atotto/go-tour-jp/gotour@latest
go: github.com/atotto/go-tour-jp/gotour@latest (in github.com/atotto/go-tour-jp@v0.0.0-20201205034358-913c5eae8455):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.

えぇ……?
調べたところ、Version1.16でモジュール管理周りで変更があり、そこに引っ掛かっている模様。
https://text.baldanders.info/golang/manage-modules/

これでバージョンを指定してモジュールのビルド&インストールができる。 ただし go.mod ファイルが replace や exclude ディレクティブを含んでいると go install が失敗するみたい。

日本語ローカライズは長らく更新がないので、おそらく対応されたとしてもずっと先だろう。
https://github.com/atotto/go-tour-jp/pull/51

公式では現行バージョン用に該当部が書き換えられている。
https://go.dev/tour/welcome/3

go get --forceのようなオプションが存在するかどうかは調べていないが、やったとしても「他に今のバージョンでは別の書き方をします」が存在しそうなので、公式の方を利用して進める。


ここまででtourのローカル起動は「CLIでファイル読ませて実行できるよ」のようなものだと勘違いしていたが、どうも実行環境とTourのサーバーをローカルに置けるよ、というだけのものであり、目的にはそぐわない。リファレンスはちゃんと読みましょう。

吉村吉村

A Tour of Go 寄り道:モジュール管理周り

go installしたものってどこに行ったんだと気になったので、その辺も調べようとしたら思いっきりTourに書いてあった。英語はちゃんと読みましょう。

This will place a tour binary in your GOPATH's bin directory. When you run the tour program, it will open a web browser displaying your local version of the tour.

  • 基本的に実行可能バイナリなんかは${GOPATH}/bin以下。変えたければ$GOBIN変えれば良さそう。
  • ビルド前のコードは${GOPATH}/pkg/mod以下に入ってくれるっぽい。
  • 依存性の管理はgo.modを利用し、モジュールの実態は全部${GOPATH}に突っ込んでる。

リファレンス読んで動かしてみた限りは上記挙動っぽい。
https://pkg.go.dev/cmd/go#hdr-GOPATH_and_Modules

現状グローバルでのモジュール管理っぽい挙動しか扱ってなく、go.modgo.sumの使い分けやら、go workspaceやらgo modやらが関連しそうだなーという感触だけど、今段階で触れると深淵に触れそうだからこのあたりで触るのやめてTourの続きを触る。

Zennでこのあたり取り扱ってくださっている方がいたので、あとで参考にするメモ。
https://zenn.dev/spiegel/articles/20210223-go-module-aware-mode

吉村吉村

A Tour of Go: Basics/Packages, variables, and functions.

内容そのもの以外で気になって調べた点についてメモ

page 1

Programs start running in package main.

go runなどで走らせる場合は、エントリポイントはmainパッケージのfunc main()でないといけない。

page 5

When two or more consecutive named function parameters share a type, you can omit the type from all but the last.

同じ型の引数を連続して記述している場合、型の宣言が省略されるよ、というもの。
このあたりもgo fmtで修正かけてくれたりするのかな?と試しにやってみたが、別にそんなことはなかった。
あくまでシュガーシンタックス扱いで、そこまで厳密に見るようなものでもないらしい。

page 11

fmtのフォーマット形式はパッケージのドキュメンテーションにある。
%を使う形式のことをなんと表現するかわからなかったのだけれど、printf formatみたいに言われるのが標準なのかな?とにかくその形式。
https://pkg.go.dev/fmt

ところでUnicodeのコードポイントをruneと表現したシンタックスにしてるのかっこよすぎんか。

吉村吉村

A Tour of Go: Flow control statements: for, if, else, switch and defer

page 5

fmt.Sprint:fmtでフォーマットだけする場合はこっち。標準出力ではなく文字列を返す。
https://pkg.go.dev/fmt#Sprint

page 12

defer全般について。
「使い方はわかったけど何に使うんやコレ」と思ったのでざっくり調べてみたら、

  • panicからのリカバー。try-finallyっぽく使う(基本的にはこれ)
  • ファイルのクローズ処理
  • テスト実行時のクリーンアップ

あたりがメインっぽい。
https://www.sohamkamani.com/golang/defer/

じゃあなんで例外処理機構用意せずdeferで解決しようとしてるんだろう、とついでに調べたらこちらの記事にお世話になった。
https://qiita.com/Maki-Daisuke/items/80cbc26ca43cca3de4e4
検査例外めんどいしRuntimeExceptionでラップして書くのも面倒だし、「できるところはrecoverで復帰してそれ以外は大域脱出」ってのは個人的にしっくりくる書き方なので、個人的にはgolangの例外処理機構の方が好みかなー。

吉村吉村

A Tour of Go: More types: structs, slices, and maps.

structs, slicesはサクッと読んで軽く叩いてみて終わり。
sliceに比べて配列の使いどころがよくわからない。基本的に実態持ってるのがarrayで、sliceでその参照(と、どこのインデックスまでの範囲からどこまでをスライスするか)を持ってるというのはわかるけど、実業務でそこまでarrayの存在気にすることあるかな……となっている。

と、ここまで考えたところでappendの挙動を思い出して検証。
appendするときは可変長の配列っぽく使えるけど、配列は値でイミュータブルかつ固定なら、新しく要素が追加されたスライスってもしかして別の配列を生成して、そこに新たに参照を持ってない?これを意識せずにappendしちゃうと元のポインタ持ちつつappend後のポインタの参照先変わっちゃう?意識してないと怖いやつ?

というわけでやってみたところ、やっぱり新たにarray生成してメモリ割り当ててる臭い挙動。ですよねー。

package main

import "fmt"

func main() {
	arr := [3]int{1, 2, 3}
	fmt.Println(&arr[0]) //0xc0000aa078
	sli := arr[:]
	fmt.Println(&sli[0]) //0xc0000aa078
	sli = append(sli, 4)
	fmt.Println(&sli[0]) //0xc0000c8030
}

ググってみた感じやっぱりallocしてる模様。ただし、この挙動をするときはcapを超えた時のみで、超えない場合は特に問題ないらしい。そりゃそうよね。

https://qiita.com/seihmd/items/d9bc98a4f4f606ecaef7
https://go.dev/blog/slices

package main

import "fmt"

func main() {
	arr := [3]int{1, 2, 3}
	fmt.Println(&arr[0]) //0xc0000aa078
	sli := arr[:]
	fmt.Println(&sli[0]) //0xc0000aa078

	sli_copy := arr[:1]
	fmt.Println(&sli_copy[0]) //0xc0000aa078
}

試してみてもそんな感じの挙動。
脳死で一方のsliceにもう一方のsliceをappendするときにforで回して1要素ずつappendしたら嫌な挙動しそう。slice同士でappendで連結できるので、こっちを使うのが良い。

Exercise: Sliceまで実施。

package main

import "golang.org/x/tour/pic"

func Pic(dx, dy int) [][]uint8 {
	result := make([][]uint8, dy)
	for i := range result {
		result[i] = make([]uint8, dx)
	}

	for y := range result {
		for x := range result[y] {
			result[y][x] = uint8((x ^ y * 3) / 2)
		}
	}

	return result
}

func main() {
	pic.Show(Pic)
}

とりあえず実装してお題に書いてあるがまま適当に式変えたりして挙動試してみたけど、これgoのお作法的に正しいのかわかんないなー。先に二重スライス作ってから値突っ込んでるけどxはfor分の中でmakeした方がいいんだろうか、など思って、先人がどうやってるのか検索したら画像大喜利してて笑った。

https://gist.github.com/tetsuok/2280162

このスクラップは2023/08/10にクローズされました