# 理解golang Interface 常見用法 >BY MTK- neuropilot - backend > 定義接口進行 類似extends func 去修改 ## interface 定義 在 Golang 中,interface 其中一個功能就是可以使用 interface `定義行為`,也就是說 interface 中可以定義一些方法來表示一個對象的行為,而當我們有`自定義`的型態假設想要擁有這些行為,就是去`實踐` interface 裡面的`方法` ## 範例 [grpahql-go](https://github.com/graphql-go/graphql/blob/master/gqlerrors/formatted.go) 的 extensions() 的接口講解 ```go= // grpahql-go type ExtendedError interface { error Extensions() map[string]interface{} } ``` 定義了 ExtendedError 的接口 必須有 1. error type 2. Extensions()的方法要返回 `map[string]interface{}` 的型態 >backend 是這樣宣告的 ```go= type Error struct { Type Type Message string cause error } // Error message func (e *Error) Error() string { return e.Message } // Cause of the original error func (e *Error) Cause() string { if e.cause != nil { return e.cause.Error() } return "" } // Extensions for graphQL extension func (e *Error) Extensions() map[string]interface{} { if e.cause != nil { log.Error().Err(e.cause).Msg("graphql error report") } return map[string]interface{}{ "code": e.Type.Code(), "type": e.Type, } } // New creates a new error func New(t Type, msg string, err error) error { return &Error{ Type: t, Message: msg, cause: err, } } ``` > 新建 error時 使用 New()這個function 並且回傳的是 指標型態 可以在Context當中操控同一個記憶體位置 ## 淺複製與深複製 - 淺複製 ```go= type Person struct { name string } func main() { p := Person{name: "Alena"} // shallow copy p2 := p fmt.Printf("%+v\n", p) // {name:Alena} fmt.Printf("%+v\n", p2) // {name:Alena} // change the copied name p2.name = "Not Alena" fmt.Printf("%+v\n", p) // {name:Alena} fmt.Printf("%+v\n", p2) // {name: Not Alena} } ``` - 深複製 ```go= package main import "fmt" type Person struct { name string } func main() { p := Person{name: "Alena"} // shallow copy p2 := &p fmt.Printf("%+v\n", p) // {name:Alena} fmt.Printf("%+v\n", p2) // {name:Alena} // change the copied name p2.name = "Not Alena" fmt.Printf("%+v\n", p) // {name:Alena} fmt.Printf("%+v\n", p2) // {name: Not Alena} } ``` 差別在於 賦值時 `p2 := p // 淺複製` `p2:= &p // 深複製` 如果沒有用指標則會導致淺複製的行為,並不是操控同一個 Struct。 ## 結論 當backend 最後return 回傳指標 &error 自定義的 Struct 並且實現 Extensions()這個function ```go= func FormatError(err error) FormattedError { switch err := err.(type) { case FormattedError: return err case *Error: ret := FormattedError{ Message: err.Error(), Locations: err.Locations, Path: err.Path, } if err := err.OriginalError; err != nil { if extended, ok := err.(ExtendedError); ok { ret.Extensions = extended.Extensions() } } return ret case Error: return FormatError(&err) default: return FormattedError{ Message: err.Error(), Locations: []location.SourceLocation{}, } } } ``` 判斷 是否有error 在進行型別判斷 是否符合 ExtendedError 的interface 若是符合就會進行 call ```ret.Extensions = extended.Extensions()``` ## (.Type) 型別判斷 * 123 * ## [參考來源](https://blog.kennycoder.io/2020/02/03/Golang-%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3interface%E5%B8%B8%E8%A6%8B%E7%94%A8%E6%B3%95/)