Golangのinterfaceでポインターを試した

# はじめに
直近はRUSTを勉強していますが、以前勉強したGolangを忘れないように、[Tour of Go](https://go-tour-jp.appspot.com/welcome/1) を利用して復習します。interfaceの理解に対して、忘れないようにここでメモを残ります。
Key: Struct, pointer, interface

# Target
part1: インタフェースでポインターを出力できるようにする
part2: インタフェースが出力タイプを指定する際に、ポインター指定クラスが利用して、errorの再定義ができる


# コード試す
## part1
~~~main.go

package main

import "fmt"

// インタフェース
type I interface {
	M()
}

// 構造体
type mystring struct {
	S string
}

// mystringのポインタクラス
func (f *mystring) M() {
	if f == nil {
		fmt.Println("<nil>")
		return
	}
	fmt.Println("print S value {}", f.S)
}

// メインメソッド
func main() {
	var i I
	var t *mystring
	i = t
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("describe the result (%v, %T)\n", i, i)
}

~~~

#### 出力結果：

~~~bash.sh
describe the result (<nil>, *main.mystring)
<nil>
~~~

ここから見ると、構造体のポインターを「t」定義して、インタフェース「i」を渡して、出力をすることができました。


~~~main.go

package main

import "fmt"

// インタフェース
type I interface {
	M()
}

// 構造体
type mystring struct {
	S string
}

// mystringのポインタクラス
func (f *mystring) M() {
	if f == nil {
		fmt.Println("<nil>")
		return
	}
	fmt.Printf("print S value is %v ,pointer is %v", f.S, &f.S)
}

// メインメソッド
func main() {
	var i I
	
	var middlestring = mystring{"Mike"}
	i = &middlestring
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("describe the result (%v, %T)\n", i, i)
}
~~~

#### 出力結果

~~~bash.sh
describe the result (&{Mike}, *main.mystring)
print S value is Mike ,pointer is 0xc000108050
~~~

ポインターを出力できました。

## part2

~~~main.go
package main

import (
	"fmt"
	"time"
)

type error interface {
	Error() string
}

type error2 interface {
	Error2() string
}

type MyError struct {
	When time.Time
	What string
}

func (e *MyError) Error2() string {
	return fmt.Sprintf("at222 %v, %s",
		e.When, e.What)
}

func (e *MyError) Error() string {
	return fmt.Sprintf("at %v, %s",
		e.When, e.What)
}

func run2() error2 {
    return &MyError{
        time.Now(), 
        "it didn't works",
    }

}

func run() error {
	return &MyError{
		time.Now(),
		"it didn't work",
	}
}

func main() {
	if err := run(); err != nil {
		fmt.Println(err)
	}
	if err2 := run2(); err2 != nil {
		fmt.Println(err2)
	}
}

~~~

#### 出力結果
~~~bash.sh
at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't work
at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't works   <- ※※おかしい 
~~~

結果からみると、run2()の返す結果は「Error()」クラスになっています。謎だ。。
error はデフォルトインタフェースのことでしょう？

~~~main.go
package main

import (
	"fmt"
	"time"
)

type error interface {
	Error() string
}

type error2 interface {
	Error2() string
}

type MyError struct {
	When time.Time
	What string
}

func (e *MyError) Error2() string {
	return fmt.Sprintf("at222 %v, %s",
		e.When, e.What)
}

func (e *MyError) Error() string {
	return fmt.Sprintf("at %v, %s",
		e.When, e.What)
}

func run2() interface{} {
    return func() interface{} {
    	var Error2 error2
    	Error2 = &MyError{time.Now(), "it didn't works"}
    	return Error2.Error2()
    }()  # <-- ここは「()」を使用しないとポインターを返す
}

func run() error {
	return &MyError{
		time.Now(),
		"it didn't work",
	}
}

func main() {
	if err := run(); err != nil {
		fmt.Println(err)
	}
	if err2 := run2(); err2 != nil {
		fmt.Println(err2)
	}
}

~~~

#### 出力結果

~~~bash.sh
at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't work
at222 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't works
~~~

結局、原因がわからないですが、一応、run2()の返す結果はinterfaceを定義し、error2 interfaceを再導入し、返す方針にして、解決できました。


# まとめ

- 既存なデフォルトインタフェースをしておくべきかな。