Try   HackMD

理解golang Interface 常見用法

BY MTK- neuropilot - backend
定義接口進行 類似extends func 去修改

interface 定義

在 Golang 中,interface 其中一個功能就是可以使用 interface 定義行為,也就是說 interface 中可以定義一些方法來表示一個對象的行為,而當我們有自定義的型態假設想要擁有這些行為,就是去實踐 interface 裡面的方法

範例

grpahql-go 的 extensions() 的接口講解

// grpahql-go type ExtendedError interface { error Extensions() map[string]interface{} }

定義了 ExtendedError 的接口 必須有

  1. error type
  2. Extensions()的方法要返回 map[string]interface{} 的型態

backend 是這樣宣告的

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當中操控同一個記憶體位置

淺複製與深複製

  • 淺複製
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} }
  • 深複製
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

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
    *

參考來源