プログラミングを始めたばかりの方や、Go言語を学び始めたばかりの方にとって、「シンプルで楽しいプロジェクト」は上達への近道です。今回の記事では、初心者でも取り組みやすい「コマンドラインで動作するToDoリストアプリ」を作成しながら、Go言語の基本的な機能である配列、スライス、構造体、関数を学びます。プログラムを理解するだけでなく、次のステップとしてデータベースやWebインターフェースの導入に繋がる内容となっています。さあ、一緒にGo言語の世界を楽しみましょう!
プログラム全体の概要
このプログラムは、コマンドラインで動作するシンプルなToDoリストアプリケーションです。以下の機能を備えています。
解説している元ファイルはGitHubからダウンロードできます。
https://github.com/miyakawa2449/go_simple_todolist
- ToDoの追加: 新しいタスクをリストに追加します。
- ToDoの一覧表示: 現在のToDoリストを表示します。
- ToDoの完了マーク: 指定したToDoを「完了」としてマークします。
- ToDoの削除: 指定したToDoをリストから削除します。
- 終了: プログラムを終了します。
主な構成要素
ToDo
構造体- タスクを表すデータ構造です。
- フィールド:
ID
: 一意の識別子。Description
: タスクの説明。Done
: タスクの完了状態(true
またはfalse
)。
- グローバル変数
todos
: 現在のToDoリストを格納するスライス。nextID
: 次に追加するタスクのID。
- 関数
main
: メインのプログラムループ。addToDo
: ToDoを追加。listToDos
: ToDoの一覧を表示。markToDoAsDone
: ToDoを「完了」にする。deleteToDo
: ToDoを削除。
ToDo
型と関連する変数の解説
Go言語では、複雑なデータ構造を扱う際に**構造体(struct)**が重要な役割を果たします。このプログラムでも、ToDo
型という構造体を定義することで、各タスクの情報を整理しています。
コード解説
type ToDo struct {
ID int
Description string
Done bool
}
- 構造体
ToDo
- 各タスクを表現するデータ型です。
- フィールド:
ID
(int型): 各タスクを一意に識別するための番号。Description
(string型): タスクの説明。Done
(bool型): タスクの完了状態を表すフラグ。true
は完了、false
は未完了を示します。
このように構造体を使うことで、関連するデータを1つの単位としてまとめて扱うことができ、プログラムが整理されます。
var todos []ToDo
var nextID int = 1
todos
(スライス)- タスクのリストを格納するスライスです。
- スライスは可変長配列のように、要素を動的に追加したり削除したりできるGo言語の便利なデータ構造です。
- プログラム内では、
append
関数を用いて新しいタスクをリストに追加しています。
nextID
(int型)- 次に作成するタスクのIDを管理する変数です。
- 初期値を
1
に設定しており、新しいタスクが追加されるたびに1ずつ増加します。 - この変数を利用して、各タスクに一意のIDを付与します。
ポイント
- 構造体の活用
- 一つのタスクに関連する情報(ID、説明、完了状態)を構造体にまとめることで、プログラムが読みやすくなり、拡張性も高まります。
- スライスの利用
- スライスは要素数を動的に変更できるため、複数のタスクを扱う場合に最適です。
- 今回のプログラムでは、スライスを使って複数のタスクをリストとして管理しています。
この部分の理解が、プログラム全体をスムーズに読み解く土台となります。構造体とスライスは、Go言語を使ったプログラムで頻繁に登場する重要な概念ですので、しっかり押さえておきましょう!
関数の詳細解説
1. main関数
func main() {
// ユーザーからの入力を処理するためにbufio.Scannerを使用。
scanner := bufio.NewScanner(os.Stdin)
for {
// メニュー表示。
fmt.Println("\n--- ToDo List ---")
fmt.Println("1. Add ToDo")
fmt.Println("2. List ToDos")
fmt.Println("3. Mark ToDo as Done")
fmt.Println("4. Delete ToDo")
fmt.Println("5. Exit")
fmt.Print("Choose an option: ")
// ユーザーの選択を取得。
scanner.Scan()
option := scanner.Text()
// 選択肢に応じて対応する処理を呼び出す。
switch option {
case "1":
addToDo(scanner)
case "2":
listToDos()
case "3":
markToDoAsDone(scanner)
case "4":
deleteToDo(scanner)
case "5":
// プログラム終了。
fmt.Println("Goodbye!")
return
default:
// 無効な入力に対するメッセージ。
fmt.Println("Invalid option, please try again.")
}
}
}
- メインループでメニューを表示し、ユーザーの入力を処理します。
- 選択肢に応じて適切な関数を呼び出します。
2. addToDo関数
func addToDo(scanner *bufio.Scanner) {
fmt.Print("Enter the ToDo description: ")
scanner.Scan()
description := scanner.Text() // ユーザーが入力した説明文を取得。
todo := ToDo{
ID: nextID,
Description: description,
Done: false, // 初期状態は未完了。
}
todos = append(todos, todo) // ToDoリストに追加。
nextID++ // 次のIDを更新。
fmt.Println("ToDo added successfully!")
}
- ユーザーにタスクの説明を入力してもらい、
todos
スライスに新しいToDo
を追加します。 - タスクの初期状態は
Done: false
です。
3. listToDos関数
func listToDos() {
if len(todos) == 0 {
fmt.Println("No ToDos available.") // 空のときのメッセージ。
return
}
fmt.Println("\nCurrent ToDos:")
for _, todo := range todos {
// 完了状態に応じてステータスを表示。
status := "Not Done"
if todo.Done {
status = "Done"
}
fmt.Printf("%d. [%s] %s\n", todo.ID, status, todo.Description)
}
}
- ToDoリストを表示します。
- 完了状態に応じて「Not Done」または「Done」を表示します。
4. markToDoAsDone関数
func markToDoAsDone(scanner *bufio.Scanner) {
fmt.Print("Enter the ID of the ToDo to mark as done: ")
scanner.Scan()
var id int
fmt.Sscanf(scanner.Text(), "%d", &id) // 入力を整数に変換。
for i, todo := range todos {
if todo.ID == id {
// 指定されたIDのタスクを「完了」に設定。
todos[i].Done = true
fmt.Println("ToDo marked as done!")
return
}
}
fmt.Println("ToDo not found.") // IDが見つからなかった場合。
}
- 指定されたIDのToDoを検索し、
Done
をtrue
にします。
5. deleteToDo関数
func deleteToDo(scanner *bufio.Scanner) {
fmt.Print("Enter the ID of the ToDo to delete: ")
scanner.Scan()
var id int
fmt.Sscanf(scanner.Text(), "%d", &id)
for i, todo := range todos {
if todo.ID == id {
// スライスからタスクを削除。
todos = append(todos[:i], todos[i+1:]...)
fmt.Println("ToDo deleted successfully!")
return
}
}
fmt.Println("ToDo not found.") // IDが見つからなかった場合。
}
- 指定されたIDのToDoをリストから削除します。
- スライス操作を利用して要素を除去します。
次のステップ
次は以下を目指しましょう。
- データベース接続:
- SQLiteなどの軽量データベースを使い、データを永続化します。
- HTMLインターフェース:
net/http
パッケージを使ってWebサーバーを構築し、ブラウザで操作できるようにします。
まとめ
この記事では、Go言語の基本的な要素を使ってシンプルなToDoリストアプリを作成しました。配列やスライスの操作、構造体を用いたデータ管理、標準入力での操作など、初学者にとって重要なトピックを網羅しています。この経験を活かし、次のステップとして以下の挑戦をおすすめします。
- データの永続化: SQLiteやMySQLを使って、データを保存する仕組みを導入。
- Webインターフェース:
net/http
パッケージを使い、HTMLを通じて操作できるように拡張。 - ファイル操作: JSONやCSVファイルを使ってデータを保存・読み込みする練習。
今回のプロジェクトを通じて、Go言語の魅力と可能性を少しでも感じていただけたなら幸いです。これからもGo言語での学習を楽しみ、ぜひあなたのアイデアを形にしてください!