Go 筆記之物件導向

pardon110發表於2019-10-26

Go語言如早期的js和python一樣,沒有顯式的類型別,但可透過結構體與函式顯式繫結,隱式地組合實現物件導向程式設計思維。

struct型別

  • struct型別初始化
    • 按照順序提供初始化值
    • 透過 field:value 的方式初始化,這樣可以任意順序
    • 透過 new 函式分配一個指標,此處P的型別為 *person
  • struct 的匿名欄位(嵌入欄位)
    • 匿名欄位能夠實現欄位的繼承
    • 所有的內建型別和自定義型別都可以作為匿名欄位
    • 同名欄位,外層的優先訪問,可過載
  • 匿名結構體

    • 空結構值struct{}{}, 通常用在通道結束符訊號,不佔記憶體
    • struct{}{name:string} 類似如其它語言中的匿名類一樣

        type Skills []string
        type Human struct {
            name string
            age int
            weight int
        }
      
        type Student struct {
            Human  // 匿名欄位,那麼預設 Student 就包含了 Human 的所有欄位
            Skills // 匿名欄位,自定義的型別 string slice
            int    // 內建型別作為匿名欄位
            speciality string
        }
      
        func main() {
            // 我們初始化一個學生
            mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
        }

物件導向

  • 方法 帶有接收者的函式

            func (r ReceiverType) funcName(parameters) (results)
            // 自定義型別,類似於別名
            type typeName typeLiteral
            type ages int
            type months map[string]int
  • 可以在任何的自定義型別中定義任意多的 method

  • 指標作為receiver

    • go 知道是否呼叫指標的 method 還是非指標的 method,會自轉
    • 如果一個 method 的 receiver 是 *T, 你可以在一個 T 型別的例項變數 V 上面呼叫method,而不需要 &V 去呼叫這個 method
  • 方法繼承 vs 重寫

    • Go使用的是內嵌式組合繼承,注意區別於其它語言,Go的‘子類’並非是‘父類’型別

interface型別

  • interface 是一組 method 簽名的組合
  • 空interface
    • interface{} 儲存任意型別的數值 (類C void*)
    • interface 函式引數
  • interface 變數儲存的型別
    • Comma-ok 斷言
      • value,ok = element(T)
      • element 為interface變數,T斷言的型別
    • element.(type) 語法不能在switch外的任何邏輯裡面使用
  • 嵌入interface

    • 相同的邏輯引入到interface內

          type Interface interface {
              sort.Interface // 嵌入欄位 sort.Interface
              Push(x interface{}) // a Push method to push elements into the heap
              Pop() interface{} // a Pop elements that pops elements from the heap
          }
      

反射

  • 結構休欄位型別

      type StructField struct {
          Name string          // 欄位名
          PkgPath string       // 欄位路徑
          Type      Type       // 欄位反射型別物件
          Tag       StructTag  // 欄位的結構體標籤
          Offset    uintptr    // 欄位在結構體中的相對偏移
          Index     []int      // Type.FieldByIndex中的返回的索引值
          Anonymous bool       // 是否為匿名欄位
      }
  • 反射某一型別的值(這些值都實現了空interface)

    1. 轉化為reflect物件(reflect.Type 或 reflect.Value)

          t := reflect.TypeOf(i)    // 得到型別的後設資料,透過t我們能獲取型別定義裡面的所有元素
          v := reflect.ValueOf(i)   // 得到實際的值,透過 v 我們獲取儲存在裡面的值,還可以去改變值
    2. 將reflect轉化為相應的值

              tag := t.Elem().Field(0).Tag  // 獲取定義在 struct 裡面的標籤
              name := v.Elem().Field(0).String()  // 獲取儲存在第一個欄位裡面的值
    3. 反射的欄位必須是可修改(可定址,即非匯出欄位不能被修改)

              var x float64 = 3.4
              v := reflect.ValueOf(x)
      
              fmt.Println("type:", v.Type())
              fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
              fmt.Println("value:", v.Float())
      
              //修改相應的值
              p := reflect.ValueOf(&x)
              v := p.Elem()
              v.SetFloat(7.1)
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章