プログラミングの基本要素
1. 変数とデータ型
変数はプログラム中でデータを一時的に格納するための箱です。
Goでは静的型付けを採用しており、変数の型を明確に指定するか、型推論を利用します。
これにより、プログラムの型安全性が保証されます。
-
型の宣言:
int
,float64
,string
,bool
など、Goには基本的なデータ型が用意されています -
型推論:
:=
演算子を使用すると、初期値に基づいて型を自動的に推論します -
ゼロ値:未初期化の変数は、型に応じたゼロ値(例えば、
int
型なら0
、string
型なら空文字列)を持ちます
サンプルコード
package main
import "fmt"
func main() {
// 明示的な型指定
var age int = 30
var height float64 = 1.75
var name string = "Taro"
// 型推論による宣言
isDeveloper := true
// ゼロ値
var uninitialized int
// 出力
fmt.Printf("名前: %s\n", name)
fmt.Printf("年齢: %d 歳\n", age)
fmt.Printf("身長: %.2f メートル\n", height)
fmt.Printf("開発者: %t\n", isDeveloper)
fmt.Printf("未初期化の整数: %d\n", uninitialized)
}
2. 定数
定数は、プログラム中で値が変更されない固定値を表します。例えば、物理定数やアプリケーション設定などに利用されます。
-
定義方法:
const
キーワードを使用して宣言します -
複数定義:
const
ブロックを使用して複数の定数を一度に定義できます - iota:連続する整数値を生成する場合に便利な特殊な識別子
サンプルコード
package main
import "fmt"
const (
Pi = 3.14159
AppName = "GoApp"
MaxUsers = 1000
// iota を使った連続値
First = iota // 0
Second // 1
Third // 2
)
func main() {
fmt.Println("アプリケーション名:", AppName)
fmt.Printf("円周率: %.5f\n", Pi)
fmt.Printf("最大ユーザー数: %d\n", MaxUsers)
fmt.Printf("連続する値: %d, %d, %d\n", First, Second, Third)
}
3. 制御構文
制御構文を用いることで、条件に応じた処理や繰り返し処理を記述できます。
Goの制御構文は、明確で読みやすいコードを書くために設計されています。
-
if文:条件式が
true
の場合に処理を実行します。括弧()
は不要です - switch文:複数の条件分岐を簡潔に記述できます。case 節に複数の値を指定可能です
-
forループ:Goでは唯一のループ構文であり、
while
やdo-while
を含む全てのパターンを表現可能です
if文の例
package main
import "fmt"
func main() {
score := 85
if score >= 90 {
fmt.Println("優秀な成績です。")
} else if score >= 70 {
fmt.Println("良い成績です。")
} else {
fmt.Println("もっと努力しましょう。")
}
}
switch文の例
package main
import "fmt"
func main() {
day := "金曜日"
switch day {
case "月曜日":
fmt.Println("週の始まりです。")
case "金曜日":
fmt.Println("お疲れ様です。週末が近いです!")
case "土曜日", "日曜日":
fmt.Println("週末を楽しみましょう!")
default:
fmt.Println("平日を乗り切りましょう!")
}
}
forループの例
package main
import "fmt"
func main() {
// カウントアップ
for i := 1; i <= 5; i++ {
fmt.Println("カウント:", i)
}
// スライスを利用したループ
numbers := []int{10, 20, 30, 40}
for index, value := range numbers {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
}
4. 関数
関数は、コードの再利用性を高めるための基本単位です。
Goでは、引数や戻り値の型を明確に指定し、シンプルで明確な関数を定義できます。
- 単一戻り値:戻り値の型を一つ指定します
- 複数戻り値:Goの特徴的な機能で、エラー処理などに頻繁に使用されます
- 可変長引数:複数の引数を受け取る場合に便利です
単一戻り値の例
package main
import "fmt"
func double(x int) int {
return x * 2
}
func main() {
result := double(10)
fmt.Printf("10の2倍: %d\n", result)
}
複数戻り値の例
package main
import "fmt"
// 商と余りを返す関数
func divide(a, b int) (int, int) {
if b == 0 {
return 0, 0 // エラーハンドリングを省略
}
return a / b, a % b
}
func main() {
quotient, remainder := divide(10, 3)
fmt.Printf("商: %d, 余り: %d\n", quotient, remainder)
}
可変長引数の例
package main
import "fmt"
// 数値を合計する関数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func main() {
result := sum(1, 2, 3, 4, 5)
fmt.Printf("合計: %d\n", result)
}
5. データ構造
Goでは、基本的なデータ構造として配列、スライス、マップ、構造体があります。
それぞれの特性を理解し、適切に使い分けることで効率的なプログラムを構築できます。
配列
配列は固定長のデータ構造で、同じ型のデータを連続して格納します。長さは宣言時に指定し、変更できません。
- 固定長のため、容量を超える要素を追加できません
- 要素にランダムアクセスが可能で高速です
package main
import "fmt"
func main() {
var arr [5]int // 長さ5の配列
arr[0] = 10
arr[1] = 20
fmt.Println("配列:", arr)
fmt.Println("配列の長さ:", len(arr))
}
スライス
スライスは可変長のデータ構造で、配列を基に動的なサイズ変更が可能です。
- 配列の一部を参照することで生成されます
-
append
関数で要素を動的に追加可能です
package main
import "fmt"
func main() {
slice := []int{10, 20, 30}
slice = append(slice, 40) // 要素を追加
fmt.Println("スライス:", slice)
fmt.Println("長さ:", len(slice))
fmt.Println("容量:", cap(slice))
}
マップ
マップはキーと値のペアを格納するデータ構造で、Goのハッシュテーブルに相当します。
- キーは一意で、値にアクセスする際に高速です
- キーの型は比較可能である必要があります(例:
int
,string
)
package main
import "fmt"
func main() {
scores := make(map[string]int) // マップの作成
scores["Alice"] = 90
scores["Bob"] = 85
fmt.Println("スコア:", scores)
fmt.Println("Aliceのスコア:", scores["Alice"])
}
構造体
構造体は複数のフィールドを持つカスタムデータ型を定義するために使用されます。
- データをグループ化して表現します
- メソッドを持たせることが可能です
package main
import "fmt"
// ユーザー構造体
type User struct {
Name string
Age int
Email string
}
func main() {
user := User{"Taro", 25, "taro@example.com"}
fmt.Printf("名前: %s, 年齢: %d, メール: %s\n", user.Name, user.Age, user.Email)
}
6. エラーハンドリング
Goはエラーハンドリングに例外ではなく、明示的なエラー値を使用します。この設計により、エラーが発生する箇所を容易に追跡できます。
基本的なエラーハンドリング
error
型はGoの組み込みインターフェースで、エラーメッセージを表現します。
package main
import (
"errors"
"fmt"
)
// エラーを返す関数
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("ゼロで割ることはできません")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("エラー:", err)
} else {
fmt.Println("結果:", result)
}
}
7. インターフェース
インターフェースは、Goの型システムにおいて非常に重要な役割を果たします。
特定のメソッドを実装することで、異なる型に共通の動作を持たせることができます。
基本的なインターフェース
package main
import "fmt"
// インターフェースの定義
type Shape interface {
Area() float64
}
// 構造体とメソッドの定義
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14 * c.Radius * c.Radius
}
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func main() {
var s Shape = Circle{Radius: 5}
fmt.Println("Circle面積:", s.Area())
s = Rectangle{Width: 4, Height: 5}
fmt.Println("Rectangle面積:", s.Area())
}
8. 標準ライブラリの活用
Goの標準ライブラリは非常に充実しており、多くのタスクを簡単に実現できます。
ここでは、特によく使われるパッケージとその使用例をいくつか紹介します。
時間操作: time
パッケージ
time
パッケージは、日付や時刻の操作を簡単に行うための機能を提供します。
現在時刻を取得
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("現在時刻:", now)
}
時間の計算
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
oneWeekLater := now.Add(7 * 24 * time.Hour) // 1週間後
fmt.Println("現在:", now)
fmt.Println("1週間後:", oneWeekLater)
}
時刻のフォーマット
Goの時刻フォーマットは独特で、特定の日付(2006-01-02 15:04:05
)を基に指定します。
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("標準形式:", now.Format("2006-01-02 15:04:05"))
fmt.Println("カスタム形式:", now.Format("2006/01/02 03:04PM"))
}
文字列操作: strings
パッケージ
strings
パッケージは、文字列操作に便利な関数を提供します。
文字列の分割
package main
import (
"fmt"
"strings"
)
func main() {
sentence := "Go is a powerful language"
words := strings.Split(sentence, " ")
fmt.Println("単語リスト:", words)
}
文字列の結合
package main
import (
"fmt"
"strings"
)
func main() {
words := []string{"Go", "is", "fun"}
sentence := strings.Join(words, " ")
fmt.Println("結合結果:", sentence)
}
部分文字列の検索
package main
import (
"fmt"
"strings"
)
func main() {
sentence := "Go is great for web development"
contains := strings.Contains(sentence, "web")
fmt.Println("含まれているか:", contains)
}
入出力操作: io
と os
パッケージ
io
と os
パッケージは、ファイルや標準入出力を操作する機能を提供します。
ファイルの作成と書き込み
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Create("example.txt")
if err != nil {
fmt.Println("ファイル作成エラー:", err)
return
}
defer file.Close()
file.WriteString("Hello, Go!\n")
fmt.Println("ファイルに書き込み完了")
}
ファイルの読み込み
package main
import (
"fmt"
"os"
)
func main() {
content, err := os.ReadFile("example.txt")
if err != nil {
fmt.Println("ファイル読み込みエラー:", err)
return
}
fmt.Println("ファイル内容:")
fmt.Println(string(content))
}
JSON操作: encoding/json
パッケージ
encoding/json
パッケージは、JSONデータのエンコードとデコードをサポートします。
構造体からJSONに変換
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
func main() {
user := User{Name: "Taro", Age: 30, Email: "taro@example.com"}
jsonData, _ := json.Marshal(user)
fmt.Println("JSONデータ:", string(jsonData))
}
JSONから構造体に変換
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
func main() {
jsonData := `{"name":"Taro","age":30,"email":"taro@example.com"}`
var user User
json.Unmarshal([]byte(jsonData), &user)
fmt.Println("構造体:", user)
}
乱数の生成: math/rand
パッケージ
math/rand
パッケージを使うと、ランダムな数値を生成できます。
ランダムな整数の生成
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("ランダム整数:", rand.Intn(100)) // 0~99
}
ランダムな小数の生成
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("ランダム小数:", rand.Float64()) // 0.0~1.0
}