Go言語触ってみた(標準出力)

# 導入

こんにちは、もんすんです。

皆さんは**Go言語**、使ったことがありますか？

私は、いつか触ろう触ろうと考えていたのですが、タイミングを見失っていました。
今回、2024年のアドベントカレンダーを進める上で、やっと機会が生まれたので、触ることにしました。

# Goについて

https://go.dev/

Go言語は、2019年11月にGoogleによって発表されたプログラミング言語です。

## 特徴

Go言語には以下のような特徴があります。

- シンプルな言語設計・文法
- 並行処理
- 標準ライブラリ群が豊富
- クロスコンパイル

などなど。

### シンプルな言語設計・文法
各機能が重複するような部分を排除した設計になっています。
例えば、繰り返し処理はfor文のみで、while文はありません。
プロジェクトごとの独自ルールを設定したり、その学習コストがかかったりすることを避けるためにこのような設計になっているそうです。

### 並行処理
`goroutine`という軽量なスレッドが、ランタイムで管理されており、各`goroutine`はメモリを共有することで、1つの変数に対して複数の`goroutine`からアクセスすることが可能になっています。

`goroutine`間でのデータの競合が発生しないように`channel`という機能が利用されています。

これらによりGoの高パフォーマンスを実現しています。

### 標準ライブラリ群が豊富

100以上の標準パッケージがあります。
サードパーティライブラリを探す前にまず、標準ライブラリに該当するものがないかは確認することが重要な気がします。

また、標準だけでなく、準標準と呼ばれるライブラリ群も用意されているようです。
`golang.org/x`以下のライブラリがそれに該当します。
これらは、十分な検証の末、標準ライブラリに転身する可能性があるライブラリ群になっており、標準ライブラリで実現したいものがなかった場合に確認すべきライブラリ群といえます。

### クロスコンパイル
開発マシンと異なるOSで動作可能な実行ファイルを生成できるらしいです。


# 触ってみた

早速触っていきます。

:::note info
今回はVSCodeのdevcontainerを利用しています。

イメージは以下の通り。
```
"image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm",
```

- Goのバージョン
```bash
go version
# go version go1.23.2 linux/amd64
```
:::

## 標準出力
まずは、確認のため、以下のコードで、標準出力を試します。

```go
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello World!")
}
```

今回は`fmt`パッケージを使用して、標準出力を行いました。
こんな感じで正しく出力することができました。

![スクリーンショット 2024-11-17 13.32.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1655179/10c3833e-3297-59e2-b459-8ef863881caa.png)

### `println`と`fmt.Println`の違い

Go言語での標準出力には、`println`と`fmt.Println`があります。
これらにはいくつかの違いがあります。

#### **`println`**
1. **基本的な標準出力**
   - Go言語に組み込まれている低レベルのデバッグ用の関数
   - `fmt`パッケージをインポートせずに使用可能
   - 書式指定や高度な出力はできない
   
2. **用途**
   - 主にデバッグ目的で使われることが想定されており、正式なコードでは推奨されない

3. **出力のフォーマット**
   - 自動的にスペースで引数を区切って出力しますが、厳密に定義されたフォーマットが保証されていません

4. **使用例**
```go
func main() {
   println("Hello, World!")
   println("Number:", 42)
}
```

5. **注意点**
   - 実行環境によって動作が異なる可能性があるため、移植性が低い
   - エラー処理やフォーマットが不要なシンプルなケース以外では、通常使用しません

#### **`fmt.Println`**
1. **高機能な標準出力**
   - `fmt`パッケージが提供する関数で、書式付きの出力が可能
   - より堅牢で移植性があり、実際のアプリケーションコードで推奨される

2. **用途**
   - フォーマット付きの出力や、信頼性の高いログ出力に使用される

3. **出力のフォーマット**
   - 自動的にスペースで区切られた引数を出力し、最後に改行が付加されます
   - フォーマットの制御には、`fmt.Printf`などと組み合わせて柔軟な制御が可能

4. **使用例**
```go
package main

import (
   "fmt"
)

func main() {
   fmt.Println("Hello World!")
   fmt.Println("Number:", 42)
}
```

5. **特徴**
   - 型に基づく適切な出力を提供
   - 他の`fmt`パッケージの関数（`Printf`, `Sprintf`など）と一貫性がある

#### **主な違いのまとめ**
| 特徴              | `println`                     | `fmt.Println`             |
|-------------------|------------------------------|---------------------------|
| **場所**          | 組み込み関数                 | `fmt`パッケージに属する   |
| **目的**          | デバッグ専用で非推奨          | 通常の出力に適している     |
| **フォーマット**   | 単純で曖昧なフォーマット       | 一貫性のあるフォーマット   |
| **移植性**        | 低い                         | 高い                      |
| **拡張性**        | なし                         | 高い（`Printf`なども利用可能）|

#### **推奨**
一般的なコードでは、移植性や拡張性が高い`fmt.Println`を使うのが良さそうです。
`println`は単純なデバッグ以外では避けるべきとされています。

## Effective Go
さて、標準出力ができたのですが、Goの作法はよくわかりません。
ですが、実はそれを体系的にまとめているサイトがあります。
それが、[Effective Go](https://go.dev/doc/effective_go)です。助かる。

また、それを翻訳しているサイトもあるみたいでした。
[Effective Go — プログラミング言語 Go ドキュメント v0.1 documentation](http://go.shibu.jp/effective_go.html)

通常のコーディングルールだけでなく、上記で少し触れた`goroutine`や`channel`についても書かれているので、取り組む前にざっと目を通しておくのが良さそうです。

私がサラッと読んで目に留まったのは以下の点です。

- パッケージ名はできるだけ短くする
    - containerVectorとかにするのではなく、cotainer/vectorのように極力1つ1つを短くするということ
- インターフェース名は、サフィックスとして`er`をつけて表現する
    - 例: ReadメソッドのIF名はReader
- 変数の宣言のみの場合は型定義が可能
    - 例: `var x int`
    - 一方、宣言と初期化を同時に行う場合は`:=`を利用し、型定義は不要になる
        - 例: `x := 10`
- for文やif文の`( )`が不要
    - 例: `for i := 0; i < 10; i++ {}`

# 終わりに
いかがでしたでしょうか？

今回はGo言語の基本的な特徴から始まり、標準出力やコーディングスタイルに触れてみました。
Goはそのシンプルさやパフォーマンス、そして豊富な標準ライブラリが魅力であり、これから学ぶ上でその強みを最大限に活かしたいと思います。