Go初心者が1日でGoを一周した内容を雑にまとめる part1
はじめに
こんにちは。今回は、モダンなプログラミング言語であるGo(ゴー)言語について紹介する。Go言語は、そのシンプルな文法と高速なコンパイル速度、そして強力な並行処理機能を特長としている。
なぜ今、Go言語を学ぶ必要があるのか、それはクラウドネイティブな開発やマイクロサービスの普及によって、Go言語の需要が急速に高まっているからである。高速な開発と高いパフォーマンスを両立できるGo言語を習得することで、エンジニアとしての市場価値を高めることが可能だ。という建前であるが、
最近の開発者としてGo言語を触れておきたいという雑な感情で学んでみた。
この記事では、Go言語の基本的な文法、変数や型、制御構文などを解説する。Go言語の魅力を感じながら、一緒にシンプルで高速な開発体験を始めよう。
Go言語の歴史と背景
Go言語誕生の背景
Go言語は、2009年にGoogleによって開発されたオープンソースのプログラミング言語である。その誕生の背景には、Google内部で使用されていた**C++**に関する課題が存在した。
- コンパイル時間の長さ:C++は実行速度が速い一方、コンパイルに非常に時間がかかる。大規模なプロジェクトでは、1台のマシンでビルドに1日以上かかることもあった。
- 安全性の問題:C++は自由度が高いため、安全にコードを書くことが難しいという課題が存在した。
これらの問題を解決するために、コンパイルが速く、安全にコードが書ける言語としてGo言語が開発された。
特徴的なコンパイラ
初期のGo言語には、「6g/8g」と「gccgo」という2種類のコンパイラが存在した。
- 6g/8g:Goの全機能をサポートし、コンパイル速度が非常に速い。ただし、生成されるバイナリの最適化が不十分。
- gccgo:GCC(GNU Compiler Collection)の最適化機能を利用し、効率的なコードを生成可能。しかし、Goの一部機能をサポートしておらず、コンパイル速度も遅い。
ジェネリックの未サポート
当初、Go言語はジェネリックをサポートしていなかった。その代替として、空インターフェースやタイプスイッチを用いて柔軟な型の扱いが可能であった。なお、最新のGoではジェネリクスが正式にサポートされている。
組み込みシステムへの適性
Go言語は動的型付けやリフレクションをサポートしているため、バイナリサイズが大きくなりがちであるため、当初は組み込みシステムでの利用に向いていないとされた。しかし、ハードウェアの性能向上により、現在では組み込み分野でも採用が進んでいる。
実際の利用例と展望
2010年時点で、Go言語の公式サイトである golang.org のWebサーバーはGoで記述されていた。開発者の一人であるRob Pike氏は、将来的にすべてのプログラムをGoで書くことを目標としている。
参考
Go言語の開発環境構築
Goのインストール方法
まずは、Go言語の公式サイトから最新のバージョンをダウンロードする。Go公式ダウンロードページ
自分のOS(Windows、macOS、Linux)に合わせたインストーラーをダウンロードし、指示に従ってインストールを完了させること。
エディタの設定
開発には、お好みのエディタを使用できるが、以下のエディタがおすすめである。
- Visual Studio Code (VS Code):軽量で拡張性が高く、Go向けの拡張機能も豊富。
- GoLand:JetBrains社が提供するGo専用の統合開発環境(IDE)で、強力な機能を備えている。
VS CodeでのGo開発環境設定例:
- VS Codeを開く
- 拡張機能マーケットプレイスで「Go」を検索
- 「Go」拡張機能をインストール
- 必要に応じて推奨される追加のツールをインストール
godocのインストールと使い方
Goの公式ドキュメントをローカル環境で閲覧できる godoc ツールをインストールしよう。
ターミナルで以下のコマンドを実行する。
go install golang.org/x/tools/cmd/godoc@latest
インストールが完了したら、godocを起動できる。
godoc -http=:6060
ブラウザで http://localhost:6060 にアクセスすると、Goのドキュメントを閲覧可能である。
godocがないと言われた時
% godoc -http=:6060
zsh: command not found: godoc
vi ~/.zshrc
で、以下を登録して保存
export GOPATH=$(go env GOPATH)
export PATH=$PATH:$GOPATH/bin
最後に、以下のコマンドを実行すると使えます
source ~/.zshrc
Hello, World! と基本的な文法
早速、Go言語でプログラムを書いてみよう。
fmt
パッケージを使った出力
Go言語で最も基本的なプログラム、「Hello, World!」を表示する。
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
実行結果:
Hello, World!
解説:
-
package main
:実行可能なプログラムのエントリポイントを示す。 -
import "fmt"
:標準パッケージのfmt
をインポートする。 -
func main()
:プログラムの開始点となる関数。 -
fmt.Println()
:標準出力に文字列を表示する。
init
関数とmain
関数の役割
init
関数は、パッケージが初期化される際に自動的に実行される関数である。
package main
import "fmt"
func init() {
fmt.Println("初期化処理")
}
func main() {
fmt.Println("メイン処理")
}
実行結果:
初期化処理
メイン処理
ポイント:
-
init
関数は複数定義可能。 -
init
関数はmain
関数よりも先に実行される。
import
の使い方と複数パッケージのインポート方法
複数のパッケージをインポートする場合は、以下のように()
を使ってまとめる。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("現在の時刻:", time.Now())
}
実行結果:
現在の時刻: 2023-10-01 12:00:00 +0000 UTC
os/user
パッケージでカレントユーザー情報を取得
現在のユーザー情報を取得する例。
package main
import (
"fmt"
"os/user"
)
func main() {
user, err := user.Current()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("現在のユーザー:", user.Username)
}
実行結果:
現在のユーザー: your_username
変数と定数
変数の宣言と初期化
Goでは、以下のように変数を宣言・初期化する。
var
キーワードを使う方法
var a int = 10
var b = 20 // 型は自動的に推論される
var s string = "Go言語"
:=
)を使う方法
短縮宣言(a := 10
b := 20
s := "Go言語"
例:
package main
import "fmt"
func main() {
var a int = 10
b := 20
s := "Go言語"
fmt.Println(a, b, s)
}
実行結果:
10 20 Go言語
複数変数の同時宣言
var (
x int
y int
z string
)
または、
x, y, z := 1, 2, "三"
var
と :=
の使い分け
-
var
:関数の外でも使える。 -
:=
:関数内でのみ使える。
例:
package main
import "fmt"
var i int = 100
func main() {
i := 200 // 関数内では新しい変数として宣言
fmt.Println(i) // 200 が表示される
}
定数の宣言
定数はconst
キーワードを使って宣言する。
const pi = 3.14
const (
Sunday = 0
Monday = 1
)
定数式
定数は計算式を使って定義することも可能。
const area = pi * 2 * 2 // 定数piを使った計算
型と型変換
基本型
- 整数型:
int
,int32
,int64
など - 浮動小数点数型:
float32
,float64
- 文字列型:
string
- 論理型:
bool
型変換
Goでは、暗黙的な型変換は行われないため、明示的に型変換を行う必要がある。
例:
package main
import (
"fmt"
"strconv"
)
func main() {
var i int = 10
var f float64 = float64(i)
fmt.Println(f) // 10.0
var s string = "20"
var j int
var err error
j, err = strconv.Atoi(s)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(j) // 20
}
}
strconv.Atoi
の内部動作解説
strconv.Atoi
は文字列を整数に変換する。
- 高速パス:短い文字列は高速に処理される。
- 低速パス:長い文字列や特定の条件下では詳細な処理が行われる。
配列
配列の宣言と初期化
var arr [3]int // 要素数3の整数型配列
arr[0] = 10
arr[1] = 20
arr[2] = 30
// 簡潔な初期化
arr := [3]int{10, 20, 30}
要素へのアクセス
fmt.Println(arr[0]) // 10
fmt.Println(arr[1]) // 20
fmt.Println(arr[2]) // 30
制御構文
defer
関数の実行が終了する直前に指定した処理を実行する。
例:
package main
import "fmt"
func main() {
defer fmt.Println("終了処理")
fmt.Println("メイン処理")
}
実行結果:
メイン処理
終了処理
panic
と recover
panic
は実行時エラーを引き起こし、recover
はそのパニック状態から復旧する。
例:
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("エラーを回復しました:", r)
}
}()
panic("予期せぬエラー")
}
実行結果:
エラーを回復しました: 予期せぬエラー
エラーハンドリングの重要性
Goでは、panic
を多用せず、エラーは戻り値として処理することが推奨されている。
ポインタ
ポインタの基本概念
ポインタは、変数のメモリアドレスを保持する。
ポインタの宣言と使い方
var n int = 100
var p *int = &n // nのアドレスを取得してポインタpに代入
fmt.Println(*p) // 100(ポインタを介して値を取得)
関数へのポインタ渡し
func increment(n *int) {
*n = *n + 1
}
func main() {
var num int = 10
increment(&num)
fmt.Println(num) // 11
}
new
関数
new
関数は指定した型のゼロ値を持つメモリを割り当て、ポインタを返す。
var p *int = new(int)
*p = 100
fmt.Println(*p) // 100
make
と new
の違い
make
関数
- スライス、マップ、チャネルの初期化に使用
- 具体的な初期化が行われる
例:
s := make([]int, 0)
m := make(map[string]int)
ch := make(chan int)
new
関数
- 指定した型のゼロ値を持つメモリを割り当て、ポインタを返す
- 値型のオブジェクトのポインタが必要なときに使用
例:
p := new(int)
fmt.Println(*p) // 0
使い分け
- make:スライス、マップ、チャネルなどの初期化
- new:その他の型のポインタを取得したいとき
構造体
Go言語の構造体は、フィールドの集まりでデータをまとめることができる。
構造体の宣言と初期化
type Person struct {
Name string
Age int
}
func main() {
person := Person{Name: "太郎", Age: 30}
fmt.Println(person)
}
実行結果:
{太郎 30}
フィールドへのアクセス
fmt.Println(person.Name) // 太郎
fmt.Println(person.Age) // 30
まとめ
今回は、Go言語の基本的な文法や特徴について雑にまとめてみた。
今後は、part2を書き、開発へ落とし込んでいきたい
Discussion