個人的な備忘録：Go言語で簡単なキーワード応答型チャットボットを作成しながら、その仕組みを紐解いてみた

## はじめに
私自身、Go言語にはあまりなじみがありませんが、今回ハッカソンのバックエンドで採用された言語ということで、キャッチアップを進めていこうと思っています。

:::note info
***これまでバックエンドの言語としてはPythonしか使ったことがなく、正直なところ他の言語についてはこれから学んでいく必要がある状況です。***
:::

なお、本記事の内容は個人的な備忘録としてまとめたものです。**その点をご理解いただければ幸いです。少しでも参考になれば嬉しいです。**

## 書こうと思ったきっかけ
普段はインフラの自動化などでYAML、JSON、Pythonを使うことが多いです。

:::note warn
**しかし、1つのプログラミング言語を徹底的に習得することで、他の言語にも知識を横展開したり流用したりできると考えています。**
:::

そのため、まずは動くものを作ってみようと思いました。

今回はその一環として、簡単なキーワード応答型のチャットボットを作成しました。***このチャットボットがどのような仕組みで動いているのか、部分的に解説していきます。***

## 簡単なアプリ概要

### Goのインストール
お使いの端末でGo言語の環境構築がまだ終わっていない場合は、過去の記事を参考にしてください。

https://qiita.com/free-honda/items/b3672e2ccfedbb14773a

### チャットボット（CLI版）について
  - **概要**: 簡単なキーワード応答型のチャットボットを作成します。
  - **機能**
    - ユーザーの入力に対して決まった応答を返す。
    - 未知の入力には「わかりません」と返答。

### コードの準備
以下のコードをローカル環境のファイル（例: main.go）に保存します。

```main.go
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	// 応答を定義
	responses := map[string]string{
		"こんにちは": "こんにちは！今日は何をしますか？",
		"ありがとう": "どういたしまして！",
		"さようなら": "またね！",
	}

	fmt.Println("チャットボットを開始します。'終了'と入力で終了します。")

	scanner := bufio.NewScanner(os.Stdin)
	for {
		fmt.Print("あなた: ")
		scanner.Scan()
		input := scanner.Text()

		// 終了コマンド
		if input == "終了" {
			fmt.Println("チャットボットを終了します。")
			break
		}

		// 応答
		if response, ok := responses[input]; ok {
			fmt.Println("ボット:", response)
		} else {
			fmt.Println("ボット: わかりません。")
		}
	}
}
```

## このGoコードの主要部分を簡単に解説

**1. パッケージとインポート**

```main.go
package main

import (
	"bufio"
	"fmt"
	"os"
)
```

  - **package main**
    - Goプログラムのエントリーポイントを定義するパッケージです。Goでは、`main`パッケージが含まれているプログラムのみ実行可能です。
  - **import**
    - 必要な外部パッケージを取り込むための構文です。ここでは次の3つをインポートしています：
      - **bufio**: 標準入力や出力を効率的に扱うためのパッケージ。
      - **fmt**: 標準出力（`Println`など）やフォーマットを扱うパッケージ。
      - **os**: オペレーティングシステムとのインターフェースを提供するパッケージ。

**2. メイン関数**

```main.go
func main() {
    // 応答を定義
    responses := map[string]string{
        "こんにちは": "こんにちは！今日は何をしますか？",
        "ありがとう": "どういたしまして！",
        "さようなら": "またね！",
    }
```

  - **func main()**
    - Goプログラムのエントリーポイントで、最初に実行される関数です。
  - **responses**
    - キー（ユーザーの入力）と値（ボットの応答）のペアを格納するマップ（`map[string]string` 型）を定義しています。
      - 例: ユーザーが「こんにちは」と入力すると、「こんにちは！今日は何をしますか？」と応答します。

**3. 標準入力の準備**

```main.go
scanner := bufio.NewScanner(os.Stdin)
```

- **scanner**
  - 標準入力を読み取るためのスキャナーを作成しています。
  - `os.Stdin` は標準入力（ターミナル）を指します。


**4. 無限ループとユーザー入力**

```main.go
for {
    fmt.Print("あなた: ")
    scanner.Scan()
    input := scanner.Text()
```

- **for {}**
  - 無限ループを表します。`break` が呼ばれるまでループを続けます。
- **scanner.Scan()**
  - ユーザーの入力を1行分スキャン（読み取り）します。
- **scanner.Text()**
  - スキャンしたテキストを文字列として取得します。

**5. 終了コマンドのチェック**

```main.go
if input == "終了" {
    fmt.Println("チャットボットを終了します。")
    break
}
```

- **終了条件**
  - ユーザーが「終了」と入力した場合にループを終了し、プログラムが終了します。

**6. 応答の処理**

```main.go
if response, ok := responses[input]; ok {
    fmt.Println("ボット:", response)
} else {
    fmt.Println("ボット: わかりません。")
}
```

- **responses[input]**
  - ユーザーの入力（`input`）に対応する応答をマップから検索します。
- **ok**
  - マップにキーが存在するかを確認します。
    - **存在する場合**: `response` に応答の文字列が格納され、応答を表示します。
    - **存在しない場合**: 「わかりません。」と応答します。

## スクリプトを実行してみた
ターミナルで保存したスクリプトを以下のコマンドで実行します。

```bash
go run main.go
```

このコマンドを実行すると、チャットボットとして動作するはずです。

**実際のコマンド結果**

```bash
➜  Desktop git:(main) ✗ go run main.go
チャットボットを開始します。'終了'と入力で終了します。
あなた: こんにちは
ボット: こんにちは！今日は何をしますか？
あなた: ありがとう
ボット: どういたしまして！
あなた: さようなら
ボット: またね！
あなた: ぴえん
ボット: わかりません。
```

***結果として、想定どおりにチャットボット形式で会話ができていることが確認できました。***

## まとめ
ここまで読んでいただき、ありがとうございました！***私の場合、とにかく「わからなくても、まず動くアプリケーションを作ってみる」ことを意識しています。***

:::note info
**細かい部分については、実際に手を動かしながら学んでいけば良いと考えています。**
:::

今後も曖昧な理解の段階でも良いので、動くものを作ることを優先し、***引き続きキャッチアップを進めていきたいと思います。***