課題3: 変数操作とスコープの理解

課題概要

変数宣言、定数、iota、スコープの理解を深めるため、設定管理システムと権限管理システムを実装します。

マンダトリー要件

要件1: 設定管理システム

異なる環境(development、staging、production)の設定を管理するプログラムを作成してください。

ファイル: config/config.go

package config

// 環境タイプ
const (
    Development = iota
    Staging
    Production
)

// 環境名
const (
    EnvDev  = "development"
    EnvStg  = "staging"
    EnvProd = "production"
)

// Config は設定を表す構造体
type Config struct {
    Environment int
    Host        string
    Port        int
    Debug       bool
    MaxRetries  int
}

// NewConfig は環境に応じた設定を返します
func NewConfig(env int) *Config {
    // TODO: 実装してください
    // - Developmentの場合: localhost:8080, Debug: true, MaxRetries: 3
    // - Stagingの場合: staging.example.com:8080, Debug: true, MaxRetries: 5
    // - Productionの場合: prod.example.com:443, Debug: false, MaxRetries: 10
}

// String は設定を文字列表現で返します
func (c *Config) String() string {
    // TODO: 実装してください
}

要件2: 権限管理システム

ビットフラグを使った権限管理システムを実装してください。

ファイル: permission/permission.go

package permission

// 権限フラグ(iotaとビットシフトを使用)
const (
    None = 0
    Read = 1 << iota
    Write
    Execute
    Delete
)

// User はユーザーと権限を表す
type User struct {
    Name        string
    Permissions int
}

// HasPermission は指定された権限を持っているか確認
func (u *User) HasPermission(perm int) bool {
    // TODO: 実装してください
}

// GrantPermission は権限を付与
func (u *User) GrantPermission(perm int) {
    // TODO: 実装してください
}

// RevokePermission は権限を剥奪
func (u *User) RevokePermission(perm int) {
    // TODO: 実装してください
}

// PermissionsString は権限を文字列表現で返す
func (u *User) PermissionsString() string {
    // TODO: 実装してください
    // 例: "Read|Write|Execute"
}

要件3: 変数スコープの実験

異なるスコープでの変数の振る舞いを示すプログラムを作成してください。

ファイル: scope/scope.go

package scope

import "fmt"

// GlobalCounter はパッケージレベル変数
var GlobalCounter int = 0

// IncrementGlobal はグローバルカウンタをインクリメント
func IncrementGlobal() {
    GlobalCounter++
}

// DemonstrateScope はスコープの違いを示す
func DemonstrateScope() {
    // TODO: 以下を実装してください
    // 1. ローカル変数 x を宣言(値: 10)
    // 2. if ブロック内で x をシャドーイング(値: 20)
    // 3. さらにネストしたブロックで x をシャドーイング(値: 30)
    // 4. 各スコープで x の値を出力
}

要件4: メインプログラム

すべての機能を統合したメインプログラムを作成してください。

ファイル: main.go

package main

import (
    "fmt"
    "yourproject/config"
    "yourproject/permission"
    "yourproject/scope"
)

func main() {
    // 設定管理のテスト
    fmt.Println("=== Config Management ===")
    devConfig := config.NewConfig(config.Development)
    fmt.Println(devConfig)

    prodConfig := config.NewConfig(config.Production)
    fmt.Println(prodConfig)

    // 権限管理のテスト
    fmt.Println("\n=== Permission Management ===")
    user := permission.User{Name: "Alice", Permissions: permission.None}

    user.GrantPermission(permission.Read)
    user.GrantPermission(permission.Write)
    fmt.Printf("%s: %s\n", user.Name, user.PermissionsString())

    if user.HasPermission(permission.Read) {
        fmt.Println("✓ Read permission granted")
    }

    user.RevokePermission(permission.Write)
    fmt.Printf("%s: %s\n", user.Name, user.PermissionsString())

    // スコープのデモンストレーション
    fmt.Println("\n=== Scope Demonstration ===")
    scope.DemonstrateScope()

    fmt.Println("\nGlobal Counter:", scope.GlobalCounter)
    scope.IncrementGlobal()
    fmt.Println("After Increment:", scope.GlobalCounter)
}

期待される出力

=== Config Management ===
Environment: development, Host: localhost:8080, Debug: true, MaxRetries: 3
Environment: production, Host: prod.example.com:443, Debug: false, MaxRetries: 10

=== Permission Management ===
Alice: Read|Write
✓ Read permission granted
Alice: Read

=== Scope Demonstration ===
Outer scope: x = 10
If block: x = 20
Inner block: x = 30
Back to if block: x = 20
Back to outer scope: x = 10

Global Counter: 0
After Increment: 1

ボーナス課題

ボーナス1: 型変換ユーティリティ

安全な型変換を行うユーティリティ関数を実装してください。

package convert

import (
    "errors"
    "strconv"
)

var (
    ErrInvalidInput = errors.New("invalid input")
    ErrOutOfRange   = errors.New("value out of range")
)

// SafeStringToInt は文字列を安全にintに変換
func SafeStringToInt(s string) (int, error) {
    // TODO: 実装してください
    // - 空文字列はエラー
    // - 数値以外はエラー
    // - intの範囲外はエラー
}

// SafeIntToUint は intを安全に uintに変換
func SafeIntToUint(i int) (uint, error) {
    // TODO: 負の数はエラー
}

// BytesToMegabytes は bytes を MB に変換
func BytesToMegabytes(bytes uint64) float64 {
    // TODO: 実装してください
}

ボーナス2: 高度な定数利用

HTTPステータスコードとエラーメッセージを定数で管理してください。

package httputil

// HTTPステータスコード
const (
    StatusOK                  = 200
    StatusCreated             = 201
    StatusBadRequest          = 400
    StatusUnauthorized        = 401
    StatusForbidden           = 403
    StatusNotFound            = 404
    StatusInternalServerError = 500
)

// エラーメッセージ
const (
    ErrMsgBadRequest   = "Bad Request"
    ErrMsgUnauthorized = "Unauthorized"
    ErrMsgNotFound     = "Not Found"
)

// GetStatusMessage はステータスコードに対応するメッセージを返す
func GetStatusMessage(code int) string {
    // TODO: switch文で実装
}

ボーナス3: ファイルサイズ定数

ファイルサイズの定数を iota で定義してください。

package filesize

import "fmt"

const (
    _ = iota // 0 をスキップ
    KB = 1 << (10 * iota)
    MB
    GB
    TB
    PB
)

// FormatSize はバイト数を人間が読みやすい形式に変換
func FormatSize(bytes uint64) string {
    // TODO: 実装してください
    // 例: 1536 → "1.50 KB"
    //     2097152 → "2.00 MB"
}

評価基準

項目 配点 詳細
設定管理システム 25点 NewConfigとStringが正しく実装されている
権限管理システム 30点 ビットフラグ操作が正しく動作する
スコープ実験 20点 各スコープでの変数の振る舞いが正しい
メインプログラム 25点 すべての機能が統合され動作する
**ボーナス1** 10点 型変換が安全に実装されている
**ボーナス2** 5点 HTTPステータスコードが適切に管理されている
**ボーナス3** 5点 ファイルサイズ変換が正しく動作する

提出方法

submission/
├── go.mod
├── main.go
├── config/
│   ├── config.go
│   └── config_test.go
├── permission/
│   ├── permission.go
│   └── permission_test.go
├── scope/
│   └── scope.go
└── bonus/
    ├── convert/
    ├── httputil/
    └── filesize/

ヒント

  • ビット演算: |(OR)で追加、&^(AND NOT)で削除
  • スコープ: 同じ名前の変数を内側のスコープで宣言すると外側を隠す
  • iota: 各constブロックで0からリセットされる
  • ゼロ値: 構造体のフィールドは自動的にゼロ値で初期化される
  • fmt.Sprintf: フォーマット済み文字列を返す
  • 学習リソース

  • Go Constants
  • Go Variables
  • Iota
  • Bit manipulation in Go