Goでinterfaceのポインタを使わない理由と使う場面

# はじめに
Goで「interfaceのポインタは使うことがない」のが定石だけど、`errors.As`のテストケースをみていて有用な場合があるのではと思った。

# interfaceのポインタ
https://golang.org/doc/faq#pointer_to_interface
をみると、

> Almost never. Pointers to interface values arise only in rare, tricky situations involving disguising an interface value's type for delayed evaluation.

にあるように、interfaceのポインタを使う場面はほぼないと言っていいようだ。
続いて以下のように続く。

> It is a common mistake to pass a pointer to an interface value to a function expecting an interface. The compiler will complain about this error but the situation can still be confusing, because sometimes a pointer is necessary to satisfy an interface. The insight is that although a pointer to a concrete type can satisfy an interface, with one exception a pointer to an interface can never satisfy an interface.

型`T`は`T`のみ、型`*T`は`T`/`*T`の両方のレシーバのメソッドを含む。
つまり、型`T`と型`*T`でメソッドセットが異なり、 **型`*T`がレシーバであるメソッドを含むinterfaceを満たすには型`T`のポインタが必ず必要**ということである。

ただし、その唯一の例外が型`T`がinterfaceの場合であり、したがって基本的にinterfaceのポインタが必要になることはない。

以下がその様子の確認である。

```golang
// Write defined as
// func (b *Buffer) Write(p []byte) (n int, err error) {..
var buf bytes.Buffer
// io.Copy(buf, os.Stdin) <- compile error
io.Copy(&buf, os.Stdin)
var writer io.Writer = &buf
// io.Copy(&writer, os.Stdin) <- compile error
io.Copy(writer, os.Stdin)	
```

# errors.Asで使う

唐突であるが、Goでのエラー処理をどう実装すべきか悩むことは多いが、個人的には
https://dave.cheney.net/paste/gocon-spring-2016.pdf
がわかりやすく、気に入っている。主題とずれるので詳しくは書かないがエッセンスとしては

* エラーの分岐処理にてどのエラーかを判断する方法として、悪い方法 -> 良い方法の順に以下
 * `if strings.Contains(err.Error(), "not found")`のように文字列比較
 * `if err == io.EOF `のように`io.EOF`等のSentinel errorと比較
 * 独自エラー型を定義して、`switch err := err.(type)`のように比較
 * interfaceにのみ依存し、`if te, ok := err.(temporary); ok && te.Temporary()`のように比較する
* エラーに付加情報を与えてエラーを返す。
  * 記事は古いが、現在では、Go1.13以降のerrorsの`Wrap`/`UnWrap`を想定すればよい

である。

ここで最も好ましいとされる方法である**interfaceとしてエラーを公開し、クライアント側でwrapされたエラーをハンドリング**することを想定する。

Go1.13以前では、https://github.com/pkg/errors を使って、

```golang
if te,ok := errors.Cause(err).(temporary); ok && te.Temporary(){
```
のようにするようにしていたが、厳密には「`Cause`は最も元となるエラーを返すので、複数回wrapしているときに意図せず取得できない」[^1]問題がある（とおもっている[^2]）。

Go1.13以降のerrorsではそもそも似たようなことはできないと勘違いしていたのだが、たまたま[errorsのテストコード](https://github.com/golang/go/blob/ce92a2023ccd77ca609126aa8a6e881c9def57f0/src/errors/wrap_test.go#L136-L151)を眺めて、interfaceのポインタを利用するとうまくできるということに気づいた。

テストコードを参考に実際の利用想定されやすいような例を作ると以下のようになる。

```golang
package main

import (
	"errors"
	"fmt"
	"os"
)

func main() {
	err := connectDatabase()
	if err != nil {
		var timeout interface{ Timeout() bool }
		// targetはnon-nilなポインタで、かつその先はinterface型かerrorをimplementしてる型である必要がある。
		if errors.As(err, &timeout) {
			fmt.Printf("Got error: %v\nTimeout return %v\n", err, timeout.Timeout())
			// 以下は確認用であり、普通のアプリケーションコードでは書かない
			if pathErr, ok := timeout.(*os.PathError); ok {
				fmt.Printf("%#v", *pathErr)
			}
		}
	}
}

func connectDatabase() error {
	err := loadConfig()
	if err != nil {
		return fmt.Errorf("failed to load database config :%w", err)
	}
	//..
	return nil
}

func loadConfig() error {
	_, err := os.Open("non-existing")
	return err
}

// OUTPUT IS BELOW
// Got error: failed to load database config :open non-existing: no such file or directory
// Timeout return false
// os.PathError{Op:"open", Path:"non-existing", Err:0x2}
```

また、[ソース](https://github.com/golang/go/blob/ce92a2023ccd77ca609126aa8a6e881c9def57f0/src/errors/wrap.go#L90-L98)をみればわかるように先述の`Cause`の問題は発生しない。

interfaceのポインタを使うべき数少ない正しい場面だと思う。



[^1]: 言葉で書くと何言っているかわからないので、[ソース](https://github.com/pkg/errors/blob/5dd12d0cfe7f152f80558d591504ce685299311e/errors.go#L280-L286)見た方が早い。

[^2]: この問題に触れているのを見かけたことがないのが個人的には不思議で間違っていないか少し不安ではある。

# [おまけ]型TはTのみ、型*TはT/*Tの両方のレシーバのメソッドを含むのはなぜか

https://golang.org/doc/faq#different_method_sets
をみると納得である。

> As the Go specification says, the method set of a type T consists of all methods with receiver type T, while that of the corresponding pointer type *T consists of all methods with receiver *T or T. That means the method set of *T includes that of T, but not the reverse.
This distinction arises because if an interface value contains a pointer *T, a method call can obtain a value by dereferencing the pointer, but if an interface value contains a value T, there is no safe way for a method call to obtain a pointer. (Doing so would allow a method to modify the contents of the value inside the interface, which is not permitted by the language specification.)

interfaceの構造はRuss Coxさんが
https://research.swtch.com/interfaces
に素晴らしい記事を書いてくれている[^3]。

interfaceにポインタ以外を代入した場合、コピーを作成し、`data`がポインタとしてそこを参照する。記事でいうと、一番最初の図の`200`がそのデータに該当する。

このメモリ領域の上書きは言語仕様上禁止されているようである。さらに仮に上書きできたとしても、`*T`をレシーバとするメソッドをcallしたクライアントから見ると（修正されるのはあくまでcopy先だから）修正が反映されていないので混乱を生み、好ましくない。

こういった理由から型`T`は`*T`がレシーバのメソッドを含まないようである。

[^3]: 記事は2009年のものでだいぶ古いので不安になるが、2021年現在の実装を軽く確認するかぎり、変わっていないよう。例えばinterfaceの定義は[ここ](https://github.com/golang/go/blob/ce92a2023ccd77ca609126aa8a6e881c9def57f0/src/runtime/runtime2.go#L202-L205)で、method tableにinterface定義のメソッドのみ含めるのは[このあたり](https://github.com/golang/go/blob/ce92a2023ccd77ca609126aa8a6e881c9def57f0/src/runtime/iface.go#L207-L236)。型がword以下の場合にポインタではなく直接`data`に該当データをいれる最適化のコードは小１時間探したが見つけることはできなかった。https://github.com/teh-cmc/go-internals/tree/master/chapter2_interfaces とか読めばわかるかもしれない。