日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

6.方法(go语言学习笔记)

發布時間:2024/4/11 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 6.方法(go语言学习笔记) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

6.方法(go語言學習筆記)


目錄

  • 定義
  • 匿名字段
  • 方法集
  • 表達式

  • 1. 定義

  • 方法是與對象實例綁定的特殊函數。
  • 方法是面向對象編程的基本概念,用于維護和展示對象的自身狀態。對象是內斂的,每個實例對象都有各自不同的獨立特征,以屬性和方法來暴露對外通信接口。
  • 普通函數則專注于算法流程,通過接收參數來完成特定邏輯運算,并返回最終結果。
  • 換句話說,方法是有關聯狀態的,而函數通常沒有。
  • 方法和函數定義的語法區別在于前者有前置實例接收參數,編譯器以此確定方法所屬類型。在某些語言中,盡管沒有顯示定義,但會在調用時隱式傳遞this實例參數。
  • 可以為當前包,以及除接口和指針以外的任何類型定義方法。
  • type N intfunc (n N) toString() string {return fmt.Sprintf("%#x", n) }func main() {var a N = 25println(a.toString()) }
  • 方法同樣不支持重載。接收參數名沒有限制,按照慣例會選用簡短有意義的名稱(不推薦用this,self)。如方法內部并不引用實例,可省略參數名,僅保留類型。
  • type N intfunc (N) test() {println("hi!") }
  • 方法可看作特殊的函數,那么receiver的類型自然可以是基礎類型或指針類型。這會關系到調用時對象實例是否被復制。
  • type N intfunc (n N) value() {n++fmt.Printf("v:%p,%v\n", &n, n)}func (n *N) pointer() {(*n)++fmt.Printf("v:%p,%v\n", n, *n) }func main() {var a N = 25a.value()fmt.Printf("a: %p,%v\n",&a,a)a.pointer()fmt.Printf("a: %p,%v\n",&a,a) }
  • 輸出
  • v: 0xc000018090,26 a: 0xc000018088,25 v: 0xc000018088,26 a: 0xc000018088,26
  • 可使用實例值或指針調用方法,編譯器會根據方法receiver類型自動在基礎類型和指針類型間轉換。
  • func main() {var a N = 25p := &aa.value() //26,但a的值沒變p.pointer() // a=26,p是a的地址p.value() //27, 但a的值還是26p.pointer() //a=27 }
  • 輸出
  • v: 0xc0000a4010,26 v: 0xc0000a4008,26 v: 0xc0000a4040,27 v: 0xc0000a4008,27
  • 不能用多級紙質調用方法。
  • 指針類型的receiver必須是合法指針(包括nil),或能獲取示例地址。
  • 如何選擇方法的receiver類型?
  • 要修改實例狀態,用 *T
  • 無需修改狀態的小對象或固定值,建議用 T
  • 大對象建議用 *T,以減少復制成本。
  • 引用類型、字符串、函數等指針包裝對象,直接用T
  • 若包含 Mutex 等同步字段,用 *T,避免因復制造成鎖操作無效
  • 其他無法確定的情況,都用 *T

  • 2. 匿名字段

  • 可以像訪問匿名字段成員那樣調用其方法,由編譯器負責查找。
  • type data struct {sync.Mutexbuf [1024]byte }func main() {d := data{}d.Lock() //編譯器會處理為 sync.(*Mutex).Lock() 調用defer d.Unlock() }
  • 方法也有同名隱蔽問題,但利用這種特性,可以實現類似覆蓋(override)操作。
  • type user struct{}type manager struct {user }func (user) toString() string {return "user" }func (m manager) toString() string {return m.user.toString()+"; manager" }func main() {var m managerprintln(m.toString())println(m.user.toString()) }
  • 輸出
  • user; manager user

    3. 方法集

  • 類型有一個與之相關的方法集(method set),這決定了它是否實現了某個接口
  • 類型T方法集包含所有receiver T方法
  • 類型 *T 方法集包含所有 receiver T+ *T方法
  • 匿名嵌入S,T方法集包含所有receiver S方法
  • 匿名嵌入 *S,T方法集包含所有receiver S+*S 方法。
  • 匿名嵌入 S 或 *S,*T方法集包含所有 receiver S+ *S 方法。
  • 方法集僅影響接口實現和方法表達式轉換,與通過實例或實例指針調用方法無關。實例并不使用方法集,而是直接調用。
  • 很顯然,匿名字段是為方法集準備的。否則,完全沒必要為少寫個字段名而大費周章。
  • 面向對象的三大特征:封裝,繼承,多態。Go僅實現了部分特征,更傾向于”組合優于繼承“思想。
  • 將模塊分解成互相獨立的更小單元,分別處理不同方面的需求,最后以匿名嵌入方式組合在一起,共同實現對外接口。
  • 其簡短一致的調用方式,更是隱藏了內部實現細節。

  • 4. 表達式

  • 方法和函數一樣,除直接調用,還可以賦值給變量,作為參數傳遞。依照具體引用方式的不同,可分為expression和value兩種狀態
  • 1. Method Expression

  • 通過類型引用的 method expression 會被還原為普通函數樣式,receiver是第一參數,調用時必須顯式傳參。至于類型,可以是T 或者 *T,只要目標方法存在于改類型方法集中即可。
  • type N intfunc (n N) test() {fmt.Printf("test.n: %p,%d\n", &n, n) }func main() {var n N = 25fmt.Printf("main.n: %p, %d\n",&n,n)f1 := N.test // func(n N)f1(n)f2 := (*N).test // func(n *N)f2(&n) //按方法集中的簽名傳遞正確類型的參數 }
  • 輸出
  • main.n:0xc000018088, 25 test.n: 0xc0000180a0,25 test.n: 0xc0000180b0,25
  • 盡管*N方法集包裝的test方法receiver類型不同,但編譯器會保證按原定義類型拷貝傳值。
  • 當然,也可直接表達式方法調用。
  • func main() {var n N = 25N.test(n)(*N).test(&n) }

    2. Method Value

  • 基于實例或指針引用的method value,參數前面不會改變,依舊按正常方式調用。
  • 但當method value被賦值給變量或者參數傳遞時,會立即計算并復制該方法執行所需的receiver對象,與其綁定,以便在稍后執行時,能隱式傳入receiver參數。
  • func main() {var n N = 100p := &nn++f1 := n.testn++f2 := p.testn++fmt.Printf("main.n:%p, %v\n",p,n)f1()f2() }
  • 輸出
  • main.n:0xc000096008, 103 test.n: 0xc000096020,101 test.n: 0xc000096030,102
  • 編譯器會為method value生成一個包裝函數,實現間接調用。至于receiver復制,和閉包的實現方法基本相同,打包成funcval,經由DX寄存器傳遞。
  • 當然,如果目標方法的receiver是指針類型,那么被復制的僅是指針。
  • type N intfunc (n *N) test() {fmt.Printf("test.n: %p,%d\n", n, *n) }func main() {var n N = 100p := &nn++f1 := n.testn++f2 := p.testn++fmt.Printf("main.n:%p, %v\n",p,n)f1()f2() }
  • 輸出
  • main.n:0xc000096008, 103 test.n: 0xc000096008,103 test.n: 0xc000096008,103
  • 只要receiver參數類型正確,使用nil同樣可以執行。
  • 總結

    以上是生活随笔為你收集整理的6.方法(go语言学习笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。