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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

go reflect 取指针_Go的方法集详解

發布時間:2025/3/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go reflect 取指针_Go的方法集详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

女主宣言

Go語言以其本身具有的高并發特性,在云計算開發中,得到了廣泛的應用,也深受廣大開發者的歡迎。但是大家對go語言真的了解了么?本文作者經過對go語言的多年實踐應用,現對go語言中的方法集進行了一次詳細的總結,并通過實驗進行了驗證,相信對于go語言愛好者有很大的幫助。下來就跟隨作者一起學習下吧。

PS:豐富的一線技術、多元化的表現形式,盡在“360云計算”,點關注哦!

1

什么是方法集

在go語言中,每個類型都有與之關聯的方法,把這個類型的所有方法稱為類型的方法集。如下:

type Student struct { age int8 name string} func (s Student) showName() { fmt.Println(s.name)} func (s * Student) setName(newName string) { s.name = newName}類型Student方法集包含了showName()方法。類型*Student方法集包含了showName()方法和setName()方法。為什么呢?因為:
  • 類型 T 方法集,包含全部 receiver T 方法。

  • 類型 *T 方法集,包含全部 receiver T + *T 方法。

2

方法集和方法接受者的關系

在上面的案例中,類型Student的方法集并不包含了setName()方法,那么是不是Student類型變量,就不能調用setName()方法呢?即下面調用,是否會報錯呢?

s := Student{}s.setName("dq")其實,上面的調用是ok的。為什么呢?我們來回顧一下go語言的方法定義。
  • 參數 receiver 可任意命名,如方法中,不使用參數,可以省略參數名。
  • 參數 receiver 類型可以是 T 或 *T,但類型T不能為接口或指針類型。
  • 不支持方法重載。
  • 實例value或pointer可以調用全部的方法,編譯器會自動轉換。

如下:

type Student struct { age int8 name string}type StudentPoint *Student func (Student) sayHello() { //省略receiver 的參數參數名字 fmt.Println("hello world")} func (s Student) showName() { fmt.Println(s.name)} func (s * Student) setName(newName string) { s.name = newName} func (s StudentPoint) showName2(){ // Error:接受者(receiver)為指針類型 fmt.Println(s.name)} s := Student{}s.setName("dq") //go會自動轉為 (&s).setName("dq") var s2 = &ss2.showName() //o會自動轉為 (*s2).showName()

所以,當類型調用自己申明的方法的時候,不需要考慮方法集。方法接受者是值類型(T),還是指針類型(*T),影響T類型的實體變量的方法集。

3

方法集和接口

接口的定義

接口是一個或多個方法簽名的集合。任何類型的方法集中只要擁有該接口“對應的全部方法”聲名。就表示它 "實現" 了該接口,無須在該類型上顯式聲明實現了哪個接口。對應的全部方法:是指有相同名稱、參數列表 (不包括參數名) 以及返回值。接口只有方法的聲明,沒有實現。接口可以匿名嵌入到其他接口,或是嵌入結構體中。接口命名習慣以 er 結尾。type Personer interface { //定義一個接口 showName()} type Student struct { Personer //嵌入接口}

接口執行機制

接口對象,是由接口表(interface table)和數據指針組成。接口表存儲元數據信息,包括接口類型、動態類型,以及實現接口的方法指針。數據指針持有的是目標對象的只讀復制品,復制完整對象或指針。package main import ( "fmt" "reflect") type User struct { id int name string} type Student struct { id int name string} func main() { u := User{1, "Tom"} var i interface{} = u // 由于interface{}不包含任何方法,所以任何類型,都實現了interface{}接口 fmt.Println(reflect.TypeOf(i)) //main.User i = Student{} fmt.Println(reflect.TypeOf(i)) //main.Student}

以實體類型和以指針類型實現接口的區別

  • 若以實體類型(T)實現接口,不管是T類型的值,還是T類型的指針,都實現了該接口。
  • 若以指針類型(*T)實現接口,只有T類型的指針,才實現了該接口。
  • type Animal interface { //接口 say()} type Dog struct { name string} type Cat struct { name string} func (_self Dog) say() { fmt.Println("I am", _self.name)} func (_self *Cat) say() { fmt.Println("I am", _self.name)} func main() { var d1 Animal= Dog{name:"wangCai1"} d1.say() //因為Dog 的value類型實現了Animal接口 var d2 Animal= &Dog{name:"wangCai2"} d2.say() //因為dDog 的指針類型實現了Animal接口 var c1 Animal= Cat{name:"miaoMiao1"} c1.say() //因為Cat 的value類型沒有實現了Animal接口,所以報錯 ???var?c2?Animal=?&Cat{name:"miaoMiao2"} c2.say() //因為Cat 的指針類型實現了Animal接口}

    類型必須實現接口的所有方法,才能表示它 "實現" 了該接口,如下:

    type Animal interface { say() doSome()} type Dog struct { name string}func (_self Dog) say() { fmt.Println("I am", _self.name)}func (_self *Dog) doSome() { fmt.Println("I will do something")} func main() { // 報錯,因為Dog的value類型實現了Animal接口的say方法沒有實現doSome方法 var d1 Animal= Dog{name:"wangCai1"} d1.say() //因為dDog 的指針類型實現了Animal接口集的所有方法 var d2 Animal= &Dog{name:"wangCai2"} d2.say() }

    4

    方法集和嵌入

    什么是嵌入

    go語言中,所謂的嵌入,即把一個類型作為另外一個類型的匿名字段。如下:

    type Person struct { age int8 name string} type Student struct { Person //嵌人 Persion類型}

    go語言通過嵌入組合,來實現繼承的行為。于是,我們就可以通過Student類型的實例,訪問Persion類型的變量和方法。如下:

    var s = Student{}s.name?=?"dq"

    值類型(T)嵌入和指針類型(*T)嵌入的區別

    type Student1 struct { Person //值類型的嵌入}type Student2 struct { *Person //指針類型的嵌入}要理解這個區別,就有知道go語言中類型的默認值。如下:
    • 數值類型(如int8、int16、uint等),默認值為0;
    • 布爾類型,默認值為false;
    • 字符串類型,默認值為""
    • 指針、通道、切片、字典等,默認值為nil
    • 復合類型的默認值,為所包含類型的默認值。
    所以:type Person struct { age int8 name string} func (s Person) showName() { fmt.Println(s.name)} func (s *Person) setName(newName string) { s.name = newName} type Student1 struct { Person //Student1包含了Person,那么Student1對應的value和pointer包含Person} type Student2 struct { *Person} // 內嵌類型 Persion默認值為 Person{age:0, name:""}s1 := Student1{}s1.setName("student1_01") // oks1.showName() // 內嵌類型 *Persion默認值為 nils2 := &Student2{}s2.setName("student1_02") //Error,由于目前內嵌類型的值為nil,會觸發報錯s2.showName() // 給嵌入類型一個復制,就ok了s3 := &Student2{Person:&Person{age:3, name:"s3"}}//s3 := &Student2{&Person{age:3, name:"s3"}} 和上一行等價s3.showName()在上面的案例中變量s2中嵌入類型默認值為nil,故會報錯:panic: runtime error: invalid memory address or nil pointer dereference所以,針對指針嵌入類型,在使用前,需要賦值。

    嵌入和方法集的關系

    • 類型 S 包含匿名字段 T,則 S和*S 方法集包含 T 方法。
    • 類型 S 包含匿名字段 *T,則 S和 *S 方法集包含 T + *T 方法。
    • 不管嵌入的是T還是*T,*S方法集,包含 T + *T 方法。
    下面,通過案例來解析,如下,思考Student1的指針和實例類型,以及Student2的指針和實例類型,是否實現了Human接口呢?type Human interface { //定義接口 showName() setName(string)} type Person struct { age int8 name string}func (s Person) showName() { // Person類型的實例和指針,都實現了Human的showName方法 fmt.Println(s.name)}func (s *Person) setName(newName string) { // 只有Person類型的指針,才實現了Human的setNanme方法 s.name = newName} type Student1 struct { // 以值類型,嵌入 Person} type Student2 struct { // 以指針類型,嵌入 *Person}解析:
  • 應用上面規則1,由于Student1通過實體類型(T)方式,嵌入Person,所以 Stuednt1的實例類型,僅僅包含了接受者為Person的方法,即不包含setName()方法,所以Student1的實例類型,沒有實現Human接口,不能賦值給Human接口;應用上面規則3, Stuednt1的指針類型,包含了接受者為Person和接受者為*Person的方法,即Stuednt1的指針類型,實現了Human接口。
  • 應用上面規則2,由于Student2通過指針類型(*T)方式,嵌入Person,所以Student2的指針類型和實例類型,都實現了Human接口。
  • 所以:// Error 應用上面的關系判斷第1條規則,因為Student1實例類型的方法集中,僅僅包含Person的實例方法集,即僅僅包含showName()方法,所以Student1的實例類型,沒有實現Human接口var s1 Human = Student1{} //報錯:Student1 does not implement Human (setName method has pointer receiver)s1.setName("student1_01")s1.showName() var s2 Human = &Student1{} //ok 應用第1條和弟3條規則s2.setName("student1_02")s2.showName() var s3 Human = Student2{&Person{}} //ok ,應用第2條規則s3.setName("student2_01")s3.showName() var s4 Human = &Student2{&Person{}} //ok ,應用第2條規則s4.setName("student2_02")s4.showName()

    360云計算

    由360云平臺團隊打造的技術分享公眾號,內容涉及數據庫、大數據、微服務、容器、AIOps、IoT等眾多技術領域,通過夯實的技術積累和豐富的一線實戰經驗,為你帶來最有料的技術分享

    總結

    以上是生活随笔為你收集整理的go reflect 取指针_Go的方法集详解的全部內容,希望文章能夠幫你解決所遇到的問題。

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