# 理解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/)