課題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