Golang
日本のGophers代表? 解説記事がある
メルカリ(プログラミング言語Go完全入門)
コードの長さ
Goは冗長な書き方となる。しかしそれがデメリットとはならない。
初心者でも導入がしやすいと裏付けられる。
Goよりもコードの密度が高く、より短く書けるプログラミング言語はある。
RubyやPythonであればコードの行数は半分から1/3になる。
Go実行速度
Goは実行速度では遅いが、コンパイルが圧倒的に早くネットワークなどのI/O速度が支配的なネットワークアプリケーションやコンテナーで動作するアプリケーションであれば十分な速度が出せる。
Goのモジュール管理
$ go env
# 1.16からGO111MODULE未指定時の規定値が`on`になった(そのためモジュールモードでやっている)
GO111MODULE=""
GOPATH モードとモジュール対応モード
Go のモジュール管理
バージョン 1.11
以降からGoツールーチェーンは以下の2つのモードのどちらかで動作する。
- GOPATHモード(GOPATH mode)
- バージョン
1.10
までのモード。標準ライブラリを除くすべてのパッケージのコード管理とビルドを環境変数GOPATHで指定されたディレクトリ下で行う。パッケージの管理はリポジトリの最新リビジョンのみが対象となる
- バージョン
- モジュール対応モード(module-aware mode)
- 標準ライブラリを除くすべてのパッケージをモジュールとして管理する。コード管理とビルドは任意のディレクトリで可能で、モジュールはリポジトリのバージョンタグまたはリビジョン毎に管理される
モジュールとは
モジュール対応モードでは、標準ライブラリを除くパッケージをモジュールとして管理する。
パッケージが単一のディレクトリを指すのに対し、モジュールは go.mod
ファルのあるディレクトリ以下の(go.modは含まない)すべてのパッケージがモジュールの配下となる。
go.sum
SHA-256
チェックサム
SHA-256
チェックサムは、データの整合性を確認するために使用されるハッシュ関数の出力。
SHA-256は「Secure Hash Algorithm 256-bit」という意味で、256ビット(32バイト)のハッシュ値を生成する。
このハッシュ値は、ファイルやデータの内容が変更されていないかどうかを確認するのに役立つ。
SHA-256 チェックサムの仕組み
- ハッシュ関数: SHA-256はハッシュ関数の一種で、任意の長さのデータを取り、固定長のハッシュ値(この場合は256ビット)を出力する
- 一意性: 同じ入力データに対しては常に同じハッシュ値が生成されます。しかし、わずかでも入力データが変わると、ハッシュ値はまったく異なるものになります。
- 逆変換不可能: ハッシュ値から元のデータを復元することは計算上非実用的です。
go.sum
ファイルにおける SHA-256 チェックサムの役割
Go言語のモジュールシステムでは、go.sum
ファイルに各依存関係のSHA-256チェックサムを記録します。これは以下の理由で重要です:
- 整合性の検証:
go.sum
ファイルに記録されたハッシュ値を使用して、依存関係のファイルが変更されていないことを確認します。これにより、ソースコードが意図せず変更されたり、悪意のあるコードが注入されたりするリスクを軽減できます。 - セキュリティ: チェックサムによって、依存関係のファイルが配信元からダウンロードされた後に変更されていないことが保証されます。これはとくにオープンソースの依存関係を使用する場合に重要です。
- 再現可能なビルド:
go.sum
に記録されたチェックサムにより、プロジェクトが依存するモジュールの正確なバージョンを保証できます。これにより、異なる環境で同じビルド結果を再現できるようになります。 要するに、go.sum
ファイルに記録されたSHA-256チェックサムは、Goプロジェクトの依存関係のセキュリティと整合性を保証するための重要な機構です。これにより、開発者は依存関係が安全で、変更されていないことに確信を持ってコードを書くことができます。
go コマンド
パッケージをインストールするとgo.modおよびgo.sumに情報が反映される。 go getやgo mod tidyによってインストールされたパッケージは$GOPATH/pkg/modに保存される。
go get [パッケージ名] # 指定したパッケージのインストール
go get # importに記載されたパッケージのインストール
go mod tidy # importに記載されたパッケージのインストール。不要なパッケージの削除
パッケージのインストールが必要なGoファイルを実行する場合、Go 1.16では go mod tidy
or go get
⇨go build
という手順。
go get オプション
go mod tidy, go get, go install違い
go mod tidy
、go install
、go get
は、Goプログラミングにおける依存関係の管理やパッケージの取得に使用されるコマンド
-
go mod tidy
:go mod tidy
コマンドは、Goモジュールの依存関係を整理するためのコマンドです。- プロジェクトの
go.mod
ファイルに記載されている依存関係を解決し、不要な依存関係を削除します。 - 使用されていないモジュールがある場合は削除し、モジュールのバージョンを最新に更新します。
- プロジェクトの依存関係を最新の状態に保つことができます。
-
go install
:go install
コマンドは、Goプログラムをビルドして実行可能なバイナリファイ ルを作成し、指定されたパッケージをインストールします。- ソースコードをビルドして実行ファイルを生成し、その実行ファイルを
$GOPATH/bin
に配置します。 - インストールされた実行ファイルは、コマンドラインから直接実行できる。
go install
を使用することで、自作のパッケージやツールを利用する他のプロジェクトから利用できる。
-
go get
:go get
コマンドは、指定したパッケージを取得し、依存関係を解決してインストールするためのコマンドです。go get
を使用することで、公開されているパッケージやモジュールを取得し、ローカルにダウンロードします。- インストールされたパッケージは、他のプロジェクトで
import
文を使用して利用できる。
メリットとしては、以下のような特徴があります:
-
go mod tidy
:- 不要な依存関係を削除してプロジェクトのモジュールを整理できます。
- モジュールのバージョンを最新の状態に保つことで、セキュリティの問題やバグの修正などの改善を取り入れることができます。
-
go install
:- 自作のパッケージやツールを他のプロジェクトから利用できるようになります。
- ビルドされた実行
ファイルを容易に実行できます。
go get
:- 公開されているパッケージやモジュールを簡単に取得できます。
- 依存関係の解決やインストール作業が自動的に行われます。
これらのコマンドを適切に使 用することで、Goプロジェクトの依存関係を管理し、必要なパッケージやモジュールを取得して開発を行うことができます。
Go モジュール・パッケージ
Goのアプリケーションとライブラリは、それぞれモジュールと呼ばれる塊になっている。 1つのフォルダーが1つのモジュールとなる。
実行ファイルorライブラリでもまず次のコマンドを叩いてプロジェクトの中心となるファイル go.mod
を作る
最後に付与するのはパッケージ名
$ go mod init hello
パッケージ 1つのファイルを複数に分割したもの。1ディレクトリ=1パッケージ
モジュール go.modファイルのあるディレクトリ以下のすべてのパッケージ(go.modは含まれない) 1レポジトリ=1モジュール
Go モジュール・パッケージをGitHubで外部に公開する場合
github.con/アカウント名/リポジトリ名/
を使う
### サンプルコードなどであれば以下のような感じでOK
$ go mod init go-example
### 公開前提の場合はモジュールのパスを指定する
$ go mod init github.com/naohito-T/go-example
Go エントリーポイント
mainパッケージは特別なパッケージ。 mainパッケージのmain関数からプログラムが開始される。
Go CLI
go fmt:コードをGo言語の標準フォーマットに変換するツール
go vet:間違えやすいコードを指摘するツール
golint:スタイルの問題を指摘するツール
godoc:コードからAPIドキュメントを作るツール
Go 歴史
昔(Go1.11以前)は $GOPATH/src
配下でしか開発できなかった。
その後Go modulesの導入により $GOPATH/src
にプロジェクトを置かなければならないという制約からは解放されたので、各プロジェクト毎に GOPATH
を指定するみたいなことがいらなくなったという経緯
そのため、こちらも現在はデフォルトから変える必要性はないです。
現在の最新歴史。これを見れば大体わかる 参考URL
Googleが開発したプログラミング言語 2009年11月に最初のバージョンをオープンソースで公開 2012年3月に正式バージョンであるGo1.0を公開 2022年5月現在の最新バージョンはGo1.18 半年毎のペースでバージョンアップ
モジュール対応モード
標準ライブラリを除くすべてのパッケージをモジュールとして管理する。 コード管理とビルドは任意のディレクトリで可能。Go1.17からは常にコレ。
モジュールとは? パッケージ: 1つのファイルを複数に分割したもの。1ディレクトリ=1パッケージ モジュール: go.modファイルのあるディレクトリ以下のすべてのパッケージ(go.modは含まれない) →1レポジトリ=1モジュール
Go 利用例
Go言語は比較的新しいプログラミング言語でありながら、世界的な動画配信サービスであるYouTubeのサーバー構築や有名Webアプリの開発などにも使用されており、人気の高い言語として世界中で愛されています。
Go 特徴
強力でシンプルな言語設計と文法 並行プログラミング 豊富な標準ライブラリ群 周辺ツールの充実 シングルバイナリ・クロスコンパイル
Go言語はC言語やJavaなどと同じく静的型付け言語でありながら、PythonやJavaScriptなどの動的型付け言語のような特徴を持つ。 Go言語はマルチプラットフォームに対応しており、Windows/macOS/Linux/Android/iOSなどの幅広いOSに対応している(クロスプラットフォームへコンパイルできる) そのため、Webアプリケーションだけでなく、スマートフォンで動作するアプリの開発も可能。
Go言語のフレームワークでもあるGobotを使用することで、ドローンやロボットなどの高度な組込みシステムの開発も可能。 Gobotにはネットワーク上のデバイスや複数のデバイス間で相互に通信できる機能があり、外出先からデバイスを操作したりセンサーが反応したときに他のデバイスと機能を連動させたりできる。
Go言語は、近年注目の集まるクラウドやコンテナーー技術、マイクロサービスなどの最新IT技術と親和性が高く、将来性のある言語
メモリ管理の手間が少ないというメリットがありますがGC(ガベレージコレクション)のアルゴリズムがSTOP THE WORLDを採用しているため、ミッションクリティカルな場面やメモリが貧弱な環境には適さない。
クロスコンパイル対応をするには
環境変数を設定する必要がある。
# Windows(32ビット)向けにコンパイル
$ GOOS=windows GOARCH=386 go build
# Linux(64ビット)向けにコンパイル
$ GOOS=linux GOARCH=amd64 go build
Go ディレクトリ構成
Go test
golangにはgo testツールなる便利なものがある。
制約
- ファイル名の最後を_test.goとしなければいけない。
- testingをimportする必要
- テストロジックの関数は
Test**
と始める。TestA or TestAbcdefgでOK - 引数には*testing.Tを入れる。
Goでのテスト結果
Goはテストのアサーションを提供していない。テストが失敗した通知に関しては、テストが失敗したことを開発者自ら実装する必要がある。
失敗したことを示すには T.Error (T.Errorf)
や T.Fatal (T.Fatalf)
を用いることができる。
T.Fatal
を用いると T.Fatal
が実行された以降のテストは呼び出されずに終了する。
テストが失敗したことを示すには T.Error
を使い、テストの初期化など、処理が失敗するとその後のテストが無意味になる場合は T.Fatal
を用いると良い。
以下のように t.Fatalf
を用いた場合は、それ以降は呼び出されないが、defer
や T.Cleanup
といった後処理は呼び出されます。
Goにおける静的解析
Goはソースコードを実行せずに解析する静的解析の機能を提供するgoパッケージが標準ライブラリとして用意されている。 そのため静的解析を用いたコードフォーマッタやLinterなどが作りやすい言語。
Go 仕組み
コンパイル
Go 変数
Goの関数や変数は、大文字からスタートするとほかのパッケージから参照できるようになる。
※小文字だと参照できない
Go言語では一度宣言した変数を使わなかったら怒られる。そのため関数の戻り値を使用しない場合は _(アンスコ)
などを使用し使用しない宣言をする。
変数の宣言と代入を同時に行う場合には := 演算子がある。 これは関数の中でしか使えない
変数命名慣例 Goの変数名は長い名前よりも短い名前が好まれる 変数のスコープが限定
変数名はどんな時にも短ければ良いわけではない。 グローバル変数にはわかりやすい名前を、ローカル変数には短い名前をこの考え方は一般的。
Go 定数
Goのconstはコンパイル時に決定できないものはconstにできない(たとえばnewとか)
パッケージ名
パッケージ名は小文字が基本 internalという名前だけはモジュール外から読めないパッケージとなる。
テストへ用いるパッケージに パッケージ名 + _test
という名前を用いることがある。
_testがついたパッケージからは公開されているパッケージの型、関数のみしか参照できない参照できないためExampleテストややブラックボックステストのような用途で使用される。
これもやめた方がいい(変数名および関数名はパッケージ名も含み考える)
// http.Serverであって、http.HTTPServerではない。
Go データ型
Goの文法ではリテラルの状態では型を持っていない。変数に代入されると型が決まる Goの場合は暗黙の型変換がなく、明示的に型変換をしなければ他の変数に代入したりできない
nil 無効な参照先を表す値
ポインター型 ポインター型の初期値はnilで、nilの参照先を取り出そうとするとプログラムがパニックを起こして終了する。 リテラルはポインターが取れない。一度変数に格納するなどが必要。
参照型 関数・スライス・マップなどは*をつけない場合もポインターと同等の動きをする。 これらは参照型と呼ばれる。 使う場合はそのままでリファレンスをせずに使われるが、コピーなどは参照のみがコピーされるされる。
スライス 多くのプログラミング言語にはリストや配列といったデータ構造はある。 →同じ型のデータが複数並んでいるデータ構造になる Goにも配列はあるが、配列ではなくスライスの方を多用する
配列やスライスは複合型と呼ばれる。
そしてスライスは配列を参照する窓のようなデータ構造 他の言語ではビューと呼ばれることがあるある。
Go 制御構文
Goが持つ制御構文は if / for / switch
if
他の言語にはたいてい falsy
の概念があるが、Goにはif文の暗黙変換がない。
boolean値のみしかif文で使用できない
for
スライスの場合はインデックスと値
マップの場合はキーと値
switch if ... else ifを羅列して書くのを簡単にしてくれるのがswitch
Go 関数
無名関数もある。 名前付き関数はパッケージレベルでしか作れないが、無名関数は関数の中でも使える。
defer
deferは関数のブロックを抜けるタイミングで処理の予約ができる。 言語が変わっても後片付けは準備と同じ場所で予約するのが一番確実の原則は一緒
エラー処理
関数の返り値にerrがある場合は err
と呼ばれる変数に代入し、その次の行でerrがnilではない(何か値が入っている)
これがエラー処理の基本。例外処理はない。
昔から変わらないGoの慣習は以下 失敗する可能性のある関数の末 尾をerror型とする
Go 構造体
構造体は中にメソッドを定義できない
type Book struct {
Title string
Author string
Publisher string
ReleasedAt time.Time
}
// インスタンス作成(フィールドはすべてゼロ値に初期化)
var b Book
// フィールドを初期化しながらインスタンス作成
b2 := Book{
Title: "sample"
}
// フィールドを初期化しながらインスタンス作成(変数にはポインター)
b3 := &Book{
Title: "sample"
}
Goではアプリケーションの実装では構造体をよく利用する。 jsonタグを定義しておくと、この定義にしたがって構造体のフィールドをJSONに書き出したり、JSONの情報フィールドにマッピングできる
Go Optional
// 引数を示す構造体
// フィールドが未指定だったのか,ゼロ値が指定されたのかを
// 区別するため,型はポインタにする⇨*string
// 引数を示す構造体
// フィールドが未指定だったのか,ゼロ値が指定されたのかを
// 区別するため,型はポインタにする
type GreetOpts struct {
GreetingWord *string
}
// オプショナルパラメータを構造体で受け取る
func Greet(name string, opts *GreetOpts) {
greetingWord := "Hello"
if opts.GreetingWord != nil {
// 引数がnilだったら未指定なのでデフォルト値で埋める
greetingWord = *opts.GreetingWord
}
fmt.Printf("%s, %s!\n", greetingWord, name)
}
func main() {
Greet("gopher", &GreetOpts{}) // Hello, gopher!
word := "Hey"
Greet("gopher", &GreetOpts{GreetingWord: &word}) // Hey, gopher!
}
Go 型
Greet("gopher", &GreetOpts{}) // &nnn &はポインタで渡す(参照))
Go import
period importとblank importという別のimportがある。
period(.) import あまりオススメはされていない
interface型
参考URL interface型 -> どんな型も格納できる特殊な型・型チェックや型変換などに使える interface -> type structの下に関数群を紐付ける書き方。オブジェクト指向でないGoにおいてclassに近しいことができる(ただし継承などはできない) 2つは本質には同じもので実装するためのメソッド(中身)のない型の使い方に過ぎない、が個人的には分けて考えたほうが考えやすかった
class
他の言語でのクラス・メンバー変数に当たる部分はGoでは構造体・フィールドとして存在する
GOROOT
GoのSDKの場所を定義している
GOPATH
ワークスペースの場所を定義している。
グローバルインストールしたパッケージなどはすべてここに保管されている
→$HOME/go/bin
※Macなら$HOME/goに自分で設定してなくても勝手に設定されてるはず(Go1.8以降)
Editor
vscodeで全 然いい
vscode拡張機能
Goをインストールすればいいだろう
Go Language Server Protocol
現状ではgoplsができており、ジャンプなどもすぐにできるようになる。
※ただし、go.mod
があるディレクトリ内でファイルを開かないといけない
go getと installの違い
go1.17から go get
を使わなくなったが go get
が完全に使えなくなるわけではない(警告はでる)
go1.16から以下の通りとなる。
go install
バイナリのビルドとインストールのため
go get
go.mod編集のための go get
go build
や go test
で自動的に go.mod
が更新され ることはなくなった。
go.modの編集は go get or go mod tidy
あるいは手作業で行います。
モジュール内で管理したいパッケージについてはこれまで通り go get
go install
はモジュール外で使いたいパッケージのインストールに使用する
Go とは
2009年11月にGoogleから発表されたプログラミング言語で、ソースコードをコンパイルして実行するコンパイル言語。 Goは得に言語のコアをシンプルに、なにかを実現するときはそのシンプルな機能を組み合わせて実現するというコンセプト
GOPATHとは
このディレクトリは、GoのソースコードやGoの実行可能ファイル、並びにコンパイル済みのパッケージファイルを保存する為に使用します。そのためこのディレクトリには3つのサブディレクトリが存在します:src、bin、pkgです。
$HOME/.go
が固定になったとのこと。go moduleになってからGOPATHの設定は不要になった。
GO PATHの構成
-
bin ビルド済の実行可能ファイル群
-
pkg ビルド済のオブジェクトファイル群(拡張子は".a") モジュールモードのときにダウンロードされるソースコード群
-
src GOPATHモードのときにダウンロードされるソースコード群 開発するソースコードを置くディレクトリ(ここで開発することが必須ではない)
goで開発するときは基本的にはGOPATHを意識して開発することになるのでとりあえずGOPATHを設定しておく。
Go のパッケージ管理方法
Go言語のパッケージ管理方法にはGOPATHモードとmodule-awareモードの2種類が存在する。
- GOPATHモードについて
- module-awareモード
Go: DepからGo Modulesへの以降
Goのモジュール管理のdepはもう古い Go modulesはGo 1.13から正式に導入されたGo言語公式の依存パッケージ管理ツール Go modules以前は、depが依存パッケージ管理のツールとしてはデフ ァクトだった。
ここからは昨今のGo moduleでの環境のsetupについて
Go moduleとは
Go moduleモードでは、GOPATH配下にプロジェクトを置かなければならないという制約からは解放された。 なので実質、GOPATHはどこをさしても構わないし、設定をされていなくてもUser/goというデフォルトの場所が決まっているため開発が楽。
- モジュールとパッケージとは モジュール = パッケージをひとつまたは複数のサブパッケージを取りまとめたカタマリ パッケージ = フォルダー単位で単一ファイルまたは複数ファイルのかたまり サブパッケージ = サブフォルダーにおくだけで扱いはパッケージと同等
あるフォルダーにてモジュールだと宣言するとそのフォルダー以下がモジュールになる。 宣言方法は以下の通り
$ go mod init <モジュール名>
こうするとカレントフォルダーにgo.modファイルが作成され、このカレントフォルダー以下がまるっと「モジュール」の扱いになります。
パッケージ名とはパッケージに置かれるGoコードの先頭に宣言される名称で、これは極力そのパッケージのフォルダー名と合致させることが推奨されます
相対パスインポートを見たらそのコードは古い可能性が高いので参考にしない様に。