Go基本文法
このセクションでは、Goの基本文法について学びます。
- Goプログラムを実行する流れ
- 演算子による数値・真偽の操作
- 変数と基本型(int、float64、string、bool)
- 型推論・短縮変数宣言・ゼロ値・定数など変数の応用
1. 事前準備
1.1 必要なツール
この章では、以下のツールを使用します。まだインストールしていない場合は、リンク先の手順に沿って準備をお願いします。
| ツール名 | 関連箇所 | 理由 |
|---|---|---|
| Visual Studio Code | Visual Studio Codeのインストール | Goのコードを記述・実行するエディタとして使用する |
| Go | Goのインストール | Goのコードを実行するランタイムとして使用する |
2. まずは動かしてみよう
文法を学ぶ前に、まずは実際に Go のプログラムを1本動かしてみましょう。細かい構文の意味は後のセクションで少しずつ扱うので、ここでは「動かす流れ」を体験することを優先します。
2.1 プロジェクトフォルダの作成
任意の場所に hello-go フォルダを作成し、Visual Studio Codeの「ファイル」→「フォルダーを開く」から、作成した hello-go フォルダを開きます。以降の操作は、Visual Studio Codeのターミナルから行います。
hello-go ← このフォルダを作成
2.2 main.go の作成
main.go を作成します。Visual Studio Codeのエクスプローラーで hello-go フォルダを右クリックし、「新しいファイル」を選択して main.go という名前で作成してください。
hello-go
└── main.go ← このファイルを作成
作成したファイルに以下の内容を記述して保存します。
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
2.3 実行
Visual Studio Codeのメニューから「ターミナル」→「新しいターミナル」を選択してターミナルを開きます。開いたターミナルで以下のコマンドを実行します。
go run main.go
go run はコンパイルと実行を一気に行うコマンドで、動作確認のために便利です。
2.4 実行結果の確認
以下のような実行結果が表示されます。
Hello, World!
Hello, World! と表示されていれば、Goのプログラムが正しく実行できています。
2.5 コードの概観
fmt.Println は、渡した文字列を標準出力に書き出す関数です。ここでは「Goのプログラムはこの形で書いて go run で動く」ことをつかめれば十分で、package main / import "fmt" / func main() / fmt.Println の詳しい意味は後のセクションで解説します。
fmt.Printlnなどの入出力関数の詳細は「Goモジュールと標準ライブラリ」のfmtパッケージで扱いますpackage main/importの役割は「Goモジュールと標準ライブラリ」で扱いますfunc main()を含む関数の書き方は「Go関数と型定義」で扱います
2.6 バイナリの生成
go run はコンパイルと実行を一気に行うため動作確認に便利ですが、実際に配布するアプリケーションでは、事前にコンパイルしたバイナリファイルを渡すのが一般的です。ここでは go build を使ってバイナリを生成し、単独で実行するまでを体験します。
以下のコマンドを実行します。
go build main.go
同じディレクトリに実行可能ファイルが生成されます。ファイル名はOSによって異なります。
- Windowsの場合:
main.exe - Mac/Linuxの場合:
main
生成されたバイナリを実行してみます。
Windowsの場合:
./main.exe
Macの場合:
./main
以下のような実行結果が表示されます。
Hello, World!
Hello, World! と表示されていれば、単一バイナリでプログラムを実行できています。単一バイナリで配布できることがGoの大きな特徴で、実行環境にGoランタイムをインストールしていなくても、生成したバイナリだけで動作します。
| 💡 ポイント |
|---|
go run と go build は用途に応じて使い分けます。ひとまず動作を確認したい・書きながら試したい場合は、コンパイルと実行を1コマンドで済ませる go run が便利です。実際に配布したい・本番のサーバに置いて動かしたい場合は、事前にコンパイル済みのバイナリを作る go build を使います。以降の講座では、動作確認を伴う場面では基本的に go run を使っていきます。 |
3. 演算子
プログラミングでは、値どうしを足したり、大きさを比べたり、条件が成り立つかを判定したりする場面が数多く登場します。こうした操作を短く記述するために、プログラミング言語には演算子(operator)と呼ばれる特別な記号が用意されています。+ や - のような算術演算子、== や < のような比較演算子、&& や || のような論理演算子など、多くの種類があります。
Goで使える演算子は他の言語とほぼ共通で、記号もほとんど同じです。ここではまず、値そのものに対する演算を通じてカテゴリごとの動きを押さえます。
3.1 演算子の分類
Goで使う演算子は、大きく以下のカテゴリに分かれます。
| カテゴリ | 主な演算子 | 用途 |
|---|---|---|
| 算術演算子 | + - * / % |
数値の四則演算と剰余 |
| 比較演算子 | == != < > <= >= |
値の大小・等価を判定して真偽値を返す |
| 論理演算子 | && || ! |
真偽値どうしの「かつ」「または」「否定」 |
| 代入演算子 | = += -= *= /= |
変数に値を代入・更新する |
ここではまず、値そのものに対する演算(算術・比較・論理)を見ていきます。変数と組み合わせた使い方や、代入時の複合演算子(+= など)は次の「変数」セクションで扱います。
3.2 算術演算子
四則演算(足し算・引き算・掛け算・割り算)は他言語と同じ記法で書けます。
package main
import "fmt"
func main() {
fmt.Println(10 + 3)
fmt.Println(10 - 3)
fmt.Println(10 * 3)
fmt.Println(10 / 3)
}
以下のような実行結果が表示されます。
13
7
30
3
整数どうしの / の結果は整数になります。上記でも 10 / 3 の結果が 3 になっており、小数点以下は切り捨てられています。小数を含めた計算を行うには、後の「変数」セクションで扱う型(float64 など)を意識する必要があります。詳しい書き方は「変数」セクションの「小数型」で改めて扱います。
3.3 剰余演算子(%)
剰余演算子 % は、割り算をしたときの余りを返す演算子です。日常の計算ではあまり使われませんが、プログラミングでは「n の倍数かどうか」「偶数か奇数か」を判定するときなどに頻繁に使われる手法です。
package main
import "fmt"
func main() {
fmt.Println(10 % 3)
fmt.Println(10 % 5)
fmt.Println(7 % 2)
}
以下のような実行結果が表示されます。
1
0
1
10 % 3 は「10 を 3 で割った余り」で 1(10 = 3 × 3 + 1)、10 % 5 は割り切れるので 0(10 = 5 × 2 + 0)、7 % 2 は奇数なので 1(7 = 2 × 3 + 1)が返ります。
代表的な使いどころは以下の2つです。
- 倍数の判定: 値を割った余りが
0なら「その数の倍数」と判定できる - 偶数・奇数の判定: 2 で割った余りが
0なら偶数、1なら奇数
実際に条件によって処理を分けるコードは、後の「Go制御構文」で if 文を学んだあとに書けるようになります。
3.4 比較演算子
比較演算子は、2つの値を比べて、その関係が成り立つかどうかを真偽値(true / false)で返す演算子です。Goでは以下の6つが用意されており、条件によって処理を切り替える場面でよく使います。
| 演算子 | 意味 |
|---|---|
== |
等しい |
!= |
等しくない |
< / > |
未満 / より大きい |
<= / >= |
以下 / 以上 |
以下、それぞれ個別に見ていきます。
== (等しい)
== は、左右の値が等しいとき true、そうでないとき false を返します。
fmt.Println(10 == 10)
fmt.Println(10 == 20)
以下のような実行結果が表示されます。
true
false
数値だけでなく、文字列や真偽値の比較にも使えます。
fmt.Println("hello" == "hello")
fmt.Println(true == false)
以下のような実行結果が表示されます。
true
false
!= (等しくない)
!= は == の逆で、左右の値が等しくないとき true を返します。
fmt.Println(10 != 20)
fmt.Println(10 != 10)
以下のような実行結果が表示されます。
true
false
< / > (未満 / より大きい)
< は「左が右より小さい(未満)」とき、> は「左が右より大きい」とき true を返します。等号は含みません。
fmt.Println(10 < 20)
fmt.Println(10 < 10)
fmt.Println(20 > 10)
以下のような実行結果が表示されます。
true
false
true
10 < 10 が false になる点に注意してください。< は「未満」なので、同じ値は含みません。
<= / >= (以下 / 以上)
<= は「左が右以下」、>= は「左が右以上」のとき true を返します。こちらは等号を含みます。
fmt.Println(10 <= 10)
fmt.Println(10 >= 10)
fmt.Println(10 <= 9)
以下のような実行結果が表示されます。
true
true
false
10 <= 10 や 10 >= 10 はいずれも true になります。「以下・以上」は同じ値を含む点が「未満・より大きい」との違いです。
3.5 論理演算子
論理演算子は、真偽値どうしを組み合わせるための演算子です。「かつ」「または」「否定」を表現でき、複数の条件を組み合わせるときに使います。Goでは以下の3つが用意されています。
| 演算子 | 意味 |
|---|---|
&& |
かつ(AND) |
|| |
または(OR) |
! |
否定(NOT) |
以下、それぞれ個別に見ていきます。
&& (かつ・AND)
&& は「左右の両方が true のとき true」を返します。どちらか一方でも false なら結果は false です。
fmt.Println(true && true)
fmt.Println(true && false)
fmt.Println(false && false)
以下のような実行結果が表示されます。
true
false
false
比較演算子と組み合わせて、「複数の条件を同時に満たすか」を判定するのに使います。
fmt.Println(85 >= 60 && 85 <= 100)
以下のような実行結果が表示されます。
true
85 >= 60(60 以上)と 85 <= 100(100 以下)の両方が true なので、結果は true になります。「点数が60〜100の範囲にあるか」といった判定でよく登場します。
|| (または・OR)
|| は「左右のどちらか一方でも true なら true」を返します。両方が false のときだけ false になります。
fmt.Println(true || false)
fmt.Println(false || true)
fmt.Println(false || false)
以下のような実行結果が表示されます。
true
true
false
比較演算子と組み合わせて、「いずれかの条件を満たすか」を判定するのに使います。
fmt.Println(50 < 60 || 50 > 100)
以下のような実行結果が表示されます。
true
50 < 60(60 未満)が true、50 > 100(100 より大きい)が false ですが、片方が true なので || の結果は true です。「範囲外か(60 未満 または 100 超)」といった判定でよく登場します。
! (否定・NOT)
! は真偽値を反転する演算子です。true を false に、false を true にします。単項演算子(右側の1つの値だけを取る)である点が他と異なります。
fmt.Println(!true)
fmt.Println(!false)
以下のような実行結果が表示されます。
false
true
比較演算子と組み合わせると、「条件が成り立たないとき」を素直に表現できます。
fmt.Println(!(10 == 20))
以下のような実行結果が表示されます。
true
10 == 20 は false、それを ! で反転して true になります。!(10 == 20) は 10 != 20 と同じ意味ですが、より複雑な条件式を反転したいときに ! は便利です。
4. 変数
4.1 変数の役割
プログラムでは、計算結果や入力データなど、あとで参照したい値を一時的に保持する必要があります。Goではその値を保持する箱として変数を使います。
4.2 まずは変数を使ってみる
シンプルな文字列を変数に入れて表示してみましょう。先ほどの hello-go プロジェクトの main.go を、以下の内容に書き換えて保存します。
package main
import "fmt"
func main() {
message := "こんにちは"
fmt.Println(message)
}
Visual Studio Codeのターミナルで以下を実行します。
go run main.go
以下のような実行結果が表示されます。
こんにちは
message := "こんにちは" の部分で、message という名前の変数に文字列 "こんにちは" を入れています。あとから message の名前を使って値を参照できます。
試しに、message に入れる文字列を "こんにちは" から "こんばんは" に変えてみましょう。
message := "こんばんは"
保存して go run main.go を再実行すると、実行結果が変わることが確認できます。
こんばんは
fmt.Println に渡しているのは message という名前のままですが、message の中身が変わったため、表示される内容も変わりました。**変数は「名前と中身をひも付ける仕組み」**であることが実感できます。
この := の書き方については後ほど詳しく紹介します。まずは「変数を用意して、あとで名前で呼び出す」流れをつかめれば十分です。
4.3 型の利用
Goは静的型付け言語と呼ばれる言語の一つで、変数ごとに「その箱に入れられる値の種類」(型)を明確に定義します。あらかじめ型を決めることで、コンパイル段階で型の不一致を検出でき、大規模なコードでも安心して改修を進められます。
| 📝 静的型付け言語とは |
|---|
| 静的型付け言語とは、変数や関数の引数・戻り値の型を、プログラムを実行する前(コンパイル時)に決めておく必要がある言語のことです。型の不一致は実行前に検出できるため、大規模開発でも型に起因するバグを早い段階で潰せます。代表例として Go・Java・TypeScript・Rust などがあります。対義語は動的型付け言語で、実行時に型が決まる Python・JavaScript・Ruby などが該当します。 |
Goで使える代表的な基本型は以下のとおりです。それぞれの詳しい使い方はこの後のサブセクションで扱います。
| 型 | 用途 | 例 |
|---|---|---|
int |
整数 | 30 |
float64 |
浮動小数点数 | 3.14 |
string |
文字列 | "hello" |
bool |
真偽値 | true / false |
4.4 型を明示した宣言(var)
Goで最も基本的な変数宣言の書き方は、var キーワードを使い、変数名のうしろに型を書く方法です。
var 変数名 型 = 初期値
実際に試してみましょう。main.go を以下の内容に書き換えます。
package main
import "fmt"
func main() {
var name string = "Taro"
var age int = 30
var height float64 = 170.5
fmt.Println(name)
fmt.Println(age)
fmt.Println(height)
}
Visual Studio Codeのターミナルで go run main.go を実行すると、以下のような実行結果が表示されます。
Taro
30
170.5
var name string = "Taro" は「string 型の name という変数を、"Taro" で初期化する」という宣言です。型を明示する書き方は、コードを読む人に「この変数はどの型を扱うか」がひと目でわかるメリットがあります。
4.5 基本型
Goで実務でもっとも頻繁に登場する基本型(文字列型・整数型・小数型・真偽値型)について、それぞれの詳しい使い方を見ていきます。
文字列型
文字列型は、文字列としてデータを扱える型です。
Goでは string として扱い、値は二重引用符 "..." で囲みます。シングルクォート '...' は使えない点に注意してください。文字列は連結演算子 + で結合できます。
package main
import "fmt"
func main() {
first := "Hello"
second := "Go"
message := first + ", " + second + "!"
fmt.Println(message)
}
以下のような実行結果が表示されます。
Hello, Go!
複数行にわたる文字列は、バッククォート ` で囲みます。
raw := `line1
line2
line3`
fmt.Println(raw)
以下のような実行結果が表示されます。
line1
line2
line3
整数型
整数型は、整数としてデータを扱える型です。
Goでは通常 int を使います。
package main
import "fmt"
func main() {
var count int = 100
fmt.Println(count + 5)
}
以下のような実行結果が表示されます。
105
int は環境(32bit/64bit OS)によって自動的にビット幅が決まるため、通常のアプリケーション開発ではまず int だけを使えば十分です。
| 💡 ポイント |
|---|
ビット幅を明示したい場面のために int8 / int16 / int32 / int64 の派生型もあります。ネットワーク越しにバイナリ列で他システムとやり取りする、ファイルフォーマットの仕様に合わせる、といった「サイズを固定したい」場合に使いますが、通常のアプリケーション開発ではまず int で問題ありません。 |
小数型
小数型は、小数としてデータを扱える型です。
Goでは通常 float64 を使います。
package main
import "fmt"
func main() {
var ratio float64 = 3.14
fmt.Println(ratio * 2)
}
以下のような実行結果が表示されます。
6.28
異なる型どうしを直接演算するとコンパイルエラーになるため、整数と小数を混ぜて計算したい場合は型変換が必要です。
var x int = 10
var y float64 = 2.5
fmt.Println(float64(x) + y)
float64(x) のように、変換したい型で値を囲むと型変換が行えます。この例では int の x を float64 に変換してから y と足し算しています。
| 💡 ポイント |
|---|
float32 という派生型もあります。メモリを節約したい場面(大量の座標データを扱うグラフィクス処理など)で使いますが、精度が下がるため、通常は float64 を使うのが無難です。 |
真偽値型
真偽値型は、Yes / No として表せる状態をデータとして扱える型です。
Goでは bool 型として扱い、true / false のいずれかの値を取ります。ゼロ値は false です。
enabled := true
fmt.Println(enabled)
以下のような実行結果が表示されます。
true
先ほど「演算子」セクションで扱った比較演算子や論理演算子の結果も、この bool 型として得られます。そのため、演算子で得た結果を変数に保持しておき、あとで使い回すこともできます。
isAdult := 20 >= 18
fmt.Println(isAdult)
以下のような実行結果が表示されます。
true
20 >= 18 の結果である true が isAdult に格納され、そのまま表示されています。isAdult は bool 型として扱われます。
4.6 型の不一致とコンパイルエラー
これまで見てきたように、Goでは変数ごとに型が決まっています。そのため、型が合わない値を代入しようとするとコンパイル段階で検出されます。たとえば以下のように、int(整数)の箱に文字列を入れようとするとコンパイルエラーになります。
var count int = "hello" // エラー: cannot use "hello" (type string) as type int
動的型付け言語(Python など)では、実行するまで型の不一致に気づけません。Goでは実行前のコンパイル段階で型の間違いを検出できるため、大規模なコードでも安心してリファクタリングできるというメリットがあります。
4.7 型推論
var で変数を宣言したさいに初期値を与えた場合、初期値から型がわかるため、型を省略できます。この仕組みを型推論と呼びます。以下は var name string = "Taro" と同じ結果になります。
var name = "Taro"
var age = 30
var height = 170.5
内部的には、"Taro" が文字列であることから name は string 型として扱われる、といった具合に型が自動で決まります。
型が推論されるだけで、静的型付けであることに変わりはありません。宣言後に別の型を入れようとすればコンパイルエラーになります。
var age = 30
age = "thirty" // エラー: cannot use "thirty" as int
一度型が決まったら、その変数は最後までその型として扱われます。
4.8 短縮変数宣言(:=)
関数の中では := を使うと、var の宣言と型推論を組み合わせた省略記法が使えます。「まずは変数を使ってみる」で登場した書き方です。
name := "Taro" // string 型に推論される
age := 30 // int 型に推論される
height := 170.5 // float64 型に推論される
いずれも初期値から型が推論されるため、明示的に string や int を書かなくてもGoが正しい型を割り当ててくれます。
:= には以下のルールがあります。
- 関数の中でしか使えない(関数の外=パッケージレベルでは
varを使う) - 変数の宣言と初期化を同時に行う場合のみ使える(既存の変数への再代入には使えず、通常の
=を使う)
実務のGoコードでは、この := が変数宣言のもっとも多い書き方になります。
4.9 代入演算子
変数の値を変更するには、通常の代入演算子 = に加えて、+= や -= などの複合代入演算子が使えます。
count := 0
count += 5
fmt.Println(count)
以下のような実行結果が表示されます。
5
count += 5 は count = count + 5 と同じ意味です。-=(減算代入)/*=(乗算代入)//=(除算代入)も同様に使えます。
4.10 インクリメント・デクリメント(++/--)
変数の値を 1 だけ増やす・減らす操作は非常に頻繁に登場するため、Goでは専用の短縮記法として ++(インクリメント)と --(デクリメント)が用意されています。
count := 5
count++
fmt.Println(count)
count--
fmt.Println(count)
以下のような実行結果が表示されます。
6
5
count++ は count = count + 1 と、count-- は count = count - 1 と同じ意味です。
式ではなく文である点に注意
他の多くの言語(JavaScript・C・Java など)では count++ は式として扱われ、以下のように別の式の中で使えます。
// JavaScript の例(Goでは不可)
console.log(count++);
しかし、Goでは count++ は文としてのみ扱われます。式として使うことは許されておらず、以下のようなコードはコンパイルエラーになります。
fmt.Println(count++) // エラー: syntax error
「式」と「文」の違いを大まかに言うと、以下のようになります。
- 式(expression): 評価すると値になるもの。関数の引数や別の演算子の右辺として使える(例:
1 + 2、x * y) - 文(statement): それ自体で1つの動作を表すが、値にはならないもの。単独の行として書く(例:
if文、代入文)
Goが ++ -- を文に限定しているのは、printf(i++, ++i) のような読みづらいコードを言語仕様レベルで防ぐためです。値を使いたい場合は、+= や通常の代入で先に変数へ入れてから使います。
count += 1
fmt.Println(count) // これは OK
| 💡 ポイント |
|---|
Goには ++count(前置インクリメント)はありません。count++ の後置形しかない点も他言語との違いです。「1増やす/減らす」という単純な操作にしか使えないぶん、コードの意図が読みやすくなっています。 |
4.11 ゼロ値と初期化なしの宣言
var 変数名 型 の形は、初期値を与えずに宣言したい場合に使います。この場合、Goが自動的に「その型のゼロ値」を代入してくれます。
package main
import "fmt"
func main() {
var count int
var message string
var enabled bool
fmt.Println(count)
fmt.Println(message)
fmt.Println(enabled)
}
以下のような実行結果が表示されます。
0
false
count は 0、message は空文字列 ""(見た目には何も表示されない)、enabled は false になりました。Goの型にはそれぞれゼロ値が定められています。
| 型 | ゼロ値 |
|---|---|
int / float64 |
0 / 0.0 |
string |
""(空文字列) |
bool |
false |
| ポインタ / スライス / マップ / チャネル | nil |
言語によっては、初期化していない変数を扱うと以下のような問題が起こります。
| 言語 | 起こる問題 | 具体的なエラー・挙動 |
|---|---|---|
| Python | 実行時にエラーで停止する | NameError: name 'count' is not defined |
| JavaScript | エラーは出ないが undefined が入り、後続の演算で NaN などになる |
console.log(count + 1) → NaN |
| C 言語 | エラーは出ず、メモリ上のゴミ(不定値)がそのまま使われる | count の中身は毎回変わる可能性があり、原因追跡が困難 |
| Java | ローカル変数はコンパイルエラー、フィールドは既定値 | variable count might not have been initialized |
Go は言語仕様レベルですべての型にゼロ値が定義されているため、var 変数名 型 と書くだけで常に安全な既定値が入ります。前掲の実行結果でも、count は 0、enabled は false と、コード上では初期値を書いていないのに問題なく動作しました。この仕組みにより、未初期化に起因する不具合(実行時エラーや不定値による予期せぬ挙動)を言語レベルで防げます。
たとえば以下のような書き方が安全に行えます。
- 集計用のカウンタを
var count intで用意し、そのままcount += ...で加算していく - エラーメッセージを
var msg stringで用意し、条件を満たしたときだけ代入する
いずれも初期値を明示的に書く必要がなく、コードがすっきり保てます。
4.12 定数
値を変更しない定数は const で宣言します。
package main
import "fmt"
func main() {
const Pi = 3.14
const AppName = "DevOpsCamp"
fmt.Println(Pi)
fmt.Println(AppName)
}
以下のような実行結果が表示されます。
3.14
DevOpsCamp
const は宣言後に値を変更できません。設定値やマジックナンバーを名前付きで扱うのに向きます。
5. まとめ
このセクションでは、Goの基本文法について学びました。
- Goのプログラムは
package mainから始まり、main関数から実行される go runは動作確認用、go buildは配布用のバイナリ生成として使い分ける- 算術・比較・論理演算子は他言語と同じ記法で使える
varと:=の2種類の書き方で変数を宣言でき、:=は関数の中でのみ使える- 文字列型・整数型・小数型・真偽値型にはゼロ値が定められており、初期化を忘れても安全な既定値が入る
- 型の異なる値どうしを演算するには型変換が必要である
- 文字列操作(
stringsパッケージ)や画面表示・標準入力(fmt/bufio)は「Goモジュールと標準ライブラリ」で扱う