1. 程式人生 > >go 函數 方法 接口

go 函數 方法 接口

fmt 斷言 lse 未定義 是否 不可 修改 src 都是

  • 概論
  • 函數
  • 方法
  • 接口

概論

  • 方法在編譯時靜態綁定,依托於具體的類型
  • 接口對應的方法是在運行時動態綁定
  • 進程內初始化順序 初始化導入包的常量和變量(可以導出的變量)--->包的init函數,不同文件內順序是未定義的, 同一文件調用順序是定義順序--->main包內的常量變量和init---->main函數

函數調用順序圖

技術分享圖片

函數

  • 可變數量的參數必須最後出現,本質是一個切片類型的參數

  • 可變參數是一個空接口類型時,調用者是否解包可變參數會導致不同的結果

    • func main() {
          var a = []interface{}{123, "abc"}
      
          Print(a...) // 123 abc 解包參數==》Print(123, "abc")
          Print(a)    // [123 abc] 不接包==》Print([]interface{}{123, "abc"})
      }
      
      func Print(a ...interface{}) {
          fmt.Println(a...)
      }
    • 空接口類型:沒有任何方法
  • 傳參都是傳值

    • append為什麽必須有返回值:因為切片結構包含底層數組的指針, 長度和容量, 函數可以通過指針修改切片內容但是長度和容量無法修改,所以必須有返回值,帶回被改變的長度和容量
  • 不用考慮堆棧位置,GC會自動設置變量存放位置

方法

  • 綁定在具體的類型,編譯時靜態綁定
  • 一個類型綁定的函數實現了接口的所有函數,這個類型就實現了這個接口
  • c實現的面向對象只用將相應的類型作為函數第一個參數傳入
  • 沒有傳統面向對象的繼承,通過組合來實現繼承

接口

  • 接口可以實現虛函數的多態性,運行時確定,延遲綁定
  • 創建一個新的接口類型滿足已經存在的具體類型而不用破壞這些類型的原有定義
  • 基礎類型不支持隱士轉換
  • 結構體內可以包含接口類型,純虛函繼承

空接口

  • 沒有任何方式

  • 空接口內部實現保存了對象的類型和指針

  • 空接口可以保存任何對象,類似於一個集裝箱,存放物品

    • // 聲明a變量, 類型int, 初始值為1
      var a int = 1
      // 聲明i變量, 類型為interface{}, 初始值為a, 此時i的值變為1
      var i interface{} = a
      // 聲明b變量, 嘗試賦值i
      var b int = i  //出錯,因為i是接口類型的,也不能顯示轉化
      var i interface{} = 5667
      j := i.(int)
      fmt.Printf("%T->%d\n", j, j) //使用類型斷言來轉換,不安全的轉化
  • 空接口比較:類型和指針比較, 兩個都一樣才一樣;

  • 不能比較空接口中的動態值

類 型 說 明
map 宕機錯誤,不可比較
切片([]T) 宕機錯誤,不可比較
通道(channel) 可比較,必須由同一個 make 生成,也就是同一個通道才會是 true,否則為 false
數組([容量]T) 可比較,編譯期知道兩個數組是否一致
結構體 可比較,可以逐個比較結構體的值
函數 可比較

類型斷言

  • x.(T) x是interface()類型, T是要斷言的類型
  • 使用場景:當某個interface{}的變量真是類型為A時才做某件事
  • 相當於賦值給void*的真實類型

go 函數 方法 接口