| <- この演算子は何者？

# はじめに

最近Goのlogパッケージの記事を読んでいたらパイプライン(| <- これ)が+のように中間演算子として使われているのを見て「なにその演算子？」となったので調べて記事にしました。
基本的に記事のコードはGoです。

# 問題のコード
```go
log.SetFlags(log.LstdFlags | log.Lshortfile)
```
ちなみに`log.LstdFlags`と`log.Lshortfile`はどちらもint型です(具体的な実装はあとにあります)。

# 公式ドキュメントにはどう書かれていたか
Goの公式言語仕様には + や - などと一緒に演算子の一つとして載っています。

```
+    sum                    integers, floats, complex values, strings
-    difference             integers, floats, complex values
*    product                integers, floats, complex values
/    quotient               integers, floats, complex values
%    remainder              integers

&    bitwise AND            integers
|    bitwise OR             integers
^    bitwise XOR            integers
&^   bit clear (AND NOT)    integers

<<   left shift             integer << unsigned integer
>>   right shift            integer >> unsigned integer
```
ですがこのドキュメントでは | は + や - と同様に、そんなん説明しなくても知ってるやろみたいな感じだったので結局この演算子が何をするものなのか分かりませんでした。その代わりbitwase ORという演算子の名前？的なものをゲットすることが出来ました。

そしてGoogleで"bitwise OR"とかなんとか検索するとbitwise ORというのはbit演算子の1つだということが分かりました。

# bit演算子とは
bit -> bit演算 -> bit演算子という順に調べて分かった事を軽く説明していきます。

## そもそもbitって何？
みなさんはご存知だと思いますがコンピュータは小さなon/offスイッチの集合で出来ています。
このスイッチのことをbitといい、それを8個ずつグループにしたものをbyteといいます。
bitだけではon offの2種類の数字 == 0と1しか表現出来ませんが、byteでは8桁の二進数として表現できます。これによってコンピュータは大きな数字の計算ができるわけですね。
`00000000`のように表記し、右端から0bit目、1bit目と数えていきます。

## bit演算って何をするの？
スイッチのon/offを制御するのがbit演算です。
基本的に8の倍数個をまとめて、つまりbyte単位で処理を行います。
bit演算はbit演算子を使って行います。

## bit演算子ってどんなものがあるの？
ここでは後の"logパッケージを読んで理解を深める"チャプターで使う4つの演算子について説明します。

### | (bitwise OR)
この記事のメインの演算子である | (bitwise OR)は二つのスイッチを比較してどちらかが1であれば1、どちらも0であれば0を返します。

e.g.

```
c = a | b
a: 01010101
b: 11001100

c: 11011101
```

### & (bitwise AND)
bitwise ORの対の演算子である & (bitwise AND)は二つのスイッチを比較してどちらも1であれば1、そうでなければ0を返します。

e.g.

```
c = a & b
a: 01010101
b: 11001100

c: 01000100
```

### << (left shift) と >> (right shift)
<< (left shift)はスイッチのon/offの状態を一つ左に、>> (right shift)は一つ右に動かします。
ずらして空いた枠には0が入り、決められた桁数を超えた場合にははみ出た部分が消えます。消える事をオーバーフローといいます。

e.g.

```
c = a << 1
a: 10101010

c: 01010100

---

c = b >> 1
b: 11001100

c: 01100110
```

### Example
少しの説明だけでは分かりづらいかな、と思ったのでPlaygroundにサンプルコードを書きました。
説明分かりづらいわ！って人はこっちを見た方が理解が早いかもしれません。
https://play.golang.org/p/wq8Dr7_SpMN

# logパッケージを読んで理解を深める
このチャプターではGoの標準パッケージであるlogパッケージを読んでbit演算子の具体的な使い方を学びます。

Go言語ではbit演算子はint型の数字に対して使う演算子であり、とりあえずこの記事ではbit演算子を数字を二進数(bitの集合)として扱うための演算子として認識しています（分かりやすくするため＆筆者の知識不足のため）。

今回は下記のコードを実行したとして読み進めていきます。

```go
package main

import "log"

func main() {
    log.SetFlags(log.LstdFlags | log.Lshortfile)
    log.Println("hoge")

    log.SetFlags(log.LstdFlags | log.Lmicroseconds)
    log.Println("fuga")
}
```

logパッケージではbit演算を使ってフラグの管理を行っています。
では実際のコードを見ていきましょう。

まず`log.SetFlags`で引数に渡している`log.LstdFlags`、`log.Lshortfile`などのフラグの定義から見ていきます。

## フラグの定義

```go
const (
    Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23 |
    Ltime                         // the time in the local time zone: 01:23:23 |
    Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime. |
    Llongfile                     // full file name and line number: /a/b/c/d.go:23 |
    Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile |
    LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone |
    Lmsgprefix                    // move the "prefix" from the beginning of the line to before the message |
    LstdFlags     = Ldate | Ltime // initial values for the standard logger |
)
```
これがフラグの定義です。`iota`というのはconst識別子で連番の整数を生成します。iotaは0から始まるので`Ldate`は`1 << 0`、`Ltime`は`1 << 1`のように続いていきます。

1は二進数で表すと`00000001`なのでそこからどんどんleft shiftでずらしていくとこんな感じになります。

| 定数名 | 値 |
|:-:|:-:|
| Ldate | 00000001 |
| Ltime | 00000010 |
| Lmicroseconds | 00000100 |
| Llongfile | 00001000 |
| Lshortfile | 00010000 |
| LUTC | 00100000 |
| Lmsgprefix | 01000000 |
| LstdFlags | 00000011 |

フラグの値を把握できたら、次はそれがどのように`log.Println`に適応されるのかを見ていきましょう。

## フラグの適応
全ての分岐を読むのは面倒なので実装の一部を切り取って説明したいと思います。
ここでは`hoge`の方を評価していると思って読んでください。

```go
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
    if l.flag&LUTC != 0 {
        t = t.UTC()
    }
    if l.flag&Ldate != 0 {
        year, month, day := t.Date()
        itoa(buf, year, 4)
        *buf = append(*buf, '/')
        itoa(buf, int(month), 2)
        *buf = append(*buf, '/')
        itoa(buf, day, 2)
        *buf = append(*buf, ' ')
    }
    if l.flag&(Ltime|Lmicroseconds) != 0 {
        hour, min, sec := t.Clock()
        itoa(buf, hour, 2)
        *buf = append(*buf, ':')
        itoa(buf, min, 2)
        *buf = append(*buf, ':')
        itoa(buf, sec, 2)
        if l.flag&Lmicroseconds != 0 {
            *buf = append(*buf, '.')
            itoa(buf, t.Nanosecond()/1e3, 6)
        }
        *buf = append(*buf, ' ')
    }
}
```

`Ldate`, `Ltime`, `Lmicroseconds`フラグを評価しているif文です。
`l.flag`というフィールドに`log.SetFlags`でセットしたフラグが入ってます。

では最初の分岐を見ていきましょう。

```go
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {...
```

ここで評価している式について詳しく見ます。
この式は`Ldate`、`Ltime`、`Lmicroseconds`フラグが与えられているか判定しています。

`l.flag`には`LstdFlags | Lshortfile`が入っているのでbitで表すと`00010011`となり、
`Ldate|Ltime|Lmicroseconds`を上の表を見て計算すると`00000111`となります。
よってbitにすると`00010011 & 00000111`の形になります。

&を計算すると `l.flag`は`00000011`(十進数に直すと3)になり、この分岐を進むことになります。

**二番目の分岐**

```go
if l.flag&LUTC != 0 {...
```

二番目の分岐は`LUTC`フラグが与えられているかを判定しています。

`l.flag`は`00010011`、`LUTC`は上の表から`00100000`なので&を計算すると`00000000`が返ってきます。
`00000000`は十進数に直しても0なのでこの分岐は進みません。
セットしていないフラグの評価はしっかり防げていますね。

三番目以降の分岐は二番目以前と大体同じなので割愛しますが、その後もしっかりセットしたフラグは評価され、セットしていないフラグは評価されないようになっています。

このチャプターの最初のコードを実行してみるとこのようになります。

```
2009/11/10 23:00:00 prog.go:7: hoge
2009/11/10 23:00:00.000000 fuga
```

`hoge`の方では`prog.go:7`のようにファイルのどこで実行したかと日時が確認でき、`Lshortfile`と日時を確認できる`LstdFlags`が評価されていることが

`fuga`の方では時刻の表記が`23:00:00.000000`とmsまで表示されるようになっており、`Lmicroseconds`が評価されていることが分かりますね。

# まとめ

今回はGoのコードで説明しましたがbit演算はGo以外のほとんど言語で実行できます。
フラグ管理にぜひbit演算を活用してみてはいかがでしょうか？

この記事では具体的な使い道としてフラグ管理を取り上げましたが、他にもたくさん使い道があるようなので気になる方はこの記事を読んでみるといいと思います！

[ビット演算 (bit 演算) の使い方を総特集！ 〜 マスクビットから bit DP まで 〜 - Qiita](https://qiita.com/drken/items/7c6ff2aa4d8fce1c9361)

あとこの記事の中でなにか間違っていることが書いてあったら遠慮せずにコメントしたり修正リクエストを送っていただきたいです。よろしくお願いします！

# 参考
[Go Tips連載8: logパッケージでログ出力している場所の情報を出す | フューチャー技術ブログ](https://future-architect.github.io/articles/20200527/)
[The Go Programming Language Specification - The Go Programming Language](https://golang.org/ref/spec)
[ビット演算入門 - Qiita](https://qiita.com/Ingward/items/43acda931c8a62c70d2f#or)
[logパッケージのソースコード](https://github.com/golang/go/blob/master/src/log/log.go)