変数の有無をnilで判断しない

## 前置き
GETのクエリ文字列を構築するときやDBの検索条件などで、オプショナルな値によってクエリ文字列やSQLの組み立て方を変える場合がある。

その時に、ポインタを使って、nilかどうかを判断する方法がたまに見られる。やめた方がいいと思っている。

関数内で上書きできるので、呼び出しもとで使っていた値が変わる可能性がある。書き換える必要があるのなら、想定通りの動きなら、問題はないが。

以下のような動きになる危険性がある。
```go
func main() {
	now := time.Now()
	fmt.Println(now.String()) // original
	pointerFunc(nil, &now)
	fmt.Println(now.String()) // add 24 hours
}

func pointerFunc(since, until *time.Time) {
	query := url.Values{}
	if since != nil {
		query.Set("since", since.Format(time.RFC3339Nano))
	}
	if until != nil {
		query.Set("until", until.Format(time.RFC3339Nano))
		*until = until.Add(24 * time.Hour)
	}
}
```
じゃあどうするのか？

## 解決案
nullableな値を使おう。
`database/sql`には、`NullInt64`がある。SpannerやBigQueryにも`NullInt64`はある。データベースに、nullableのフィールドがある際に使用される。
とはいえ、これはデータベースとのやりとりで使用されるものであるし、任意のnullable typeではない。

なので、自分でパッケージを作った。任意のtypeに対するnullableが使えるようにした。

「ポインタを使って、nilでないならば〜」が無くなる。
「`f(&v)`か`f(nil)`で、オプショナルな値を渡して〜」が無くなる。
「`var v *type`で`f(v)`で、オプショナルな値を渡して〜」が無くなる。

### 以下、パッケージの説明
(この記事よりもGitHubにあるコードの方がアップデートされやすいので、これは、現時点での情報）

https://github.com/taniko/nullable

```sh
go get github.com/taniko/nullable
```

使い方（READMEより）
```go
package main

import (
	"fmt"

	"github.com/taniko/nullable"
)

func main() {
	var v nullable.Nullable[string]
	fmt.Println(v.IsNull()) // true

	v = nullable.New("text")
	fmt.Println(v.IsNull()) // false
	fmt.Println(v.Value())  // text
}
```

こんな感じで書くことができる。
最初に書いたオプショナルなsince, untilをnullableで書き直す。
ポインタがなくなった。これで、どこかで値を書き換えられる心配は無くなった。
```go
package main

import (
	"net/url"
	"time"

	"github.com/taniko/nullable"
)

func main() {
	var since, until nullable.Nullable[time.Time]
	until = nullable.New(time.Now())
	f(since, until)
}

func f(since, until nullable.Nullable[time.Time]) {
	query := url.Values{}
	if !since.IsNull() {
		query.Set("since", since.Value().Format(time.RFC3339Nano))
	}
	if !until.IsNull() {
		query.Set("until", until.Value().Format(time.RFC3339Nano))
	}
}

```

「任意の型で〜」と言ったので、当然ながら以下のようにできる
```go
package main

import (
	"fmt"

	"github.com/taniko/nullable"
)

type User struct {
	ID   string
	Name string
}

func main() {
	var user nullable.Nullable[User]
	fmt.Println(user.IsNull())
	user = nullable.New(User{
		ID:   "id",
		Name: "name",
	})
	fmt.Println(user.IsNull())
}
```

ついでに、json.Marshalの際には、nullになる。
```go
type User struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}
type Data struct {
	User nullable.Nullable[User] `json:"user"`
}

func main() {
	var data Data
	if err := marshal(data); err != nil {
		panic(err)
	}

	data.User = nullable.New(User{
		ID:   "123",
		Name: "abc",
	})
	if err := marshal(data); err != nil {
		panic(err)
	}
}

func marshal(data Data) error {
	b, err := json.Marshal(data)
	if err != nil {
		return err
	}
	fmt.Println(string(b))
	return nil
}
```
```text
{"user":null}
{"user":{"id":"123","name":"abc"}}
```

### 注意事項
現在stableなgomock(v1.6)では、genericsがサポートされていないので、このnullableパッケージは使用できない。
ただし、直接、引数や返り値で指定できないだけで、struct内にあるフィールドとしてnullableが使用されている分には問題ない。

ちなみに、genericsのサポートは、v1.7.0で入る予定(v1.7.0-rc.1)だったが、長らくstableの更新がされず。また、最近、gomockのパッケージが、`github.com/golang/mock`から`go.uber.org/mock`へと移行された。
いつgenericsに対応されるかは、以下のリポジトリのページで確認しよう。

https://github.com/uber/mock