欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > Go語言中的方法、接口和嵌入類型詳解

Go語言中的方法、接口和嵌入類型詳解

熱門標簽:旅游廁所如何電子地圖標注 外呼系統如何接收服務密碼 智能營銷軟件 外呼系統多少錢一年 工商信用卡外呼系統教程 滁州自建外呼系統 經常接到推銷電話機器人的電話 客服級電銷機器人 海外照相館地圖標注入駐

概述

在 Go 語言中,如果一個結構體和一個嵌入字段同時實現了相同的接口會發生什么呢?我們猜一下,可能有兩個問題:

1.編譯器會因為我們同時有兩個接口實現而報錯嗎?
2.如果編譯器接受這樣的定義,那么當接口調用時編譯器要怎么確定該使用哪個實現?

在寫了一些測試代碼并認真深入的讀了一下標準之后,我發現了一些有意思的東西,而且覺得很有必要分享出來,那么讓我們先從 Go 語言中的方法開始說起。

方法

Go 語言中同時有函數和方法。一個方法就是一個包含了接受者的函數,接受者可以是命名類型或者結構體類型的一個值或者是一個指針。所有給定類型的方法屬于該類型的方法集。

下面定義一個結構體類型和該類型的一個方法:

復制代碼 代碼如下:

type User struct {
  Name  string
  Email string
}

func (u User) Notify() error

首先我們定義了一個叫做 User 的結構體類型,然后定義了一個該類型的方法叫做 Notify,該方法的接受者是一個 User 類型的值。要調用 Notify 方法我們需要一個 User 類型的值或者指針:

復制代碼 代碼如下:

// User 類型的值可以調用接受者是值的方法
damon := User{"AriesDevil", "ariesdevil@xxoo.com"}
damon.Notify()

// User 類型的指針同樣可以調用接受者是值的方法
alimon := User{"A-limon", "alimon@ooxx.com"}
alimon.Notify()

在這個例子中當我們使用指針時,Go 調整和解引用指針使得調用可以被執行。注意,當接受者不是一個指針時,該方法操作對應接受者的值的副本(意思就是即使你使用了指針調用函數,但是函數的接受者是值類型,所以函數內部操作還是對副本的操作,而不是指針操作,參見:http://play.golang.org/p/DBhWU0p1Pv)。

我們可以修改 Notify 方法,讓它的接受者使用指針類型:

復制代碼 代碼如下:

func (u *User) Notify() error

再來一次之前的調用(注意:當接受者是指針時,即使用值類型調用那么函數內部也是對指針的操作,參見:http://play.golang.org/p/SYBb4xPfPh):

復制代碼 代碼如下:

// User 類型的值可以調用接受者是指針的方法
damon := User{"AriesDevil", "ariesdevil@xxoo.com"}
damon.Notify()

// User 類型的指針同樣可以調用接受者是指針的方法
alimon := User{"A-limon", "alimon@ooxx.com"}
alimon.Notify()

如果你不清楚到底什么時候該使用值,什么時候該使用指針作為接受者,你可以去看一下這篇介紹。這篇文章同時還包含了社區約定的接受者該如何命名。

接口

Go 語言中的接口很特別,而且提供了難以置信的一系列靈活性和抽象性。它們指定一個特定類型的值和指針表現為特定的方式。從語言角度看,接口是一種類型,它指定一個方法集,所有方法為接口類型就被認為是該接口。

下面定義一個接口:

復制代碼 代碼如下:

type Notifier interface {
  Notify() error
}

我們定義了一個叫做 Notifier 的接口并包含一個 Notify 方法。當一個接口只包含一個方法時,按照 Go 語言的約定命名該接口時添加 -er 后綴。這個約定很有用,特別是接口和方法具有相同名字和意義的時候。

我們可以在接口中定義盡可能多的方法,不過在 Go 語言標準庫中,你很難找到一個接口包含兩個以上的方法。

實現接口

當涉及到我們該怎么讓我們的類型實現接口時,Go 語言是特別的一個。Go 語言不需要我們顯式的實現類型的接口。如果一個接口里的所有方法都被我們的類型實現了,那么我們就說該類型實現了該接口。

讓我們繼續之前的例子,定義一個函數來接受任意一個實現了接口 Notifier 的類型的值或者指針:

復制代碼 代碼如下:

func SendNotification(notify Notifier) error {
  return notify.Notify()
}

SendNotification 函數調用 Notify 方法,這個方法被傳入函數的一個值或者指針實現。這樣一來一個函數就可以被用來執行任意一個實現了該接口的值或者指針的指定的行為。

用我們的 User 類型來實現該接口并且傳入一個 User 類型的值來調用 SendNotification 方法:

復制代碼 代碼如下:

func (u *User) Notify() error {
  log.Printf("User: Sending User Email To %s%s>\n",
      u.Name,
      u.Email)
  return nil
}

func main() {
  user := User{
    Name:  "AriesDevil",
    Email: "ariesdevil@xxoo.com",
  }
 
  SendNotification(user)
}

// Output:
cannot use user (type User) as type Notifier in function argument:
User does not implement Notifier (Notify method has pointer receiver)

詳細代碼:http://play.golang.org/p/KG8-Qb7gqM

為什么編譯器不考慮我們的值是實現該接口的類型?接口的調用規則是建立在這些方法的接受者和接口如何被調用的基礎上。下面的是語言規范里定義的規則,這些規則用來說明是否我們一個類型的值或者指針實現了該接口:

1.類型 *T 的可調用方法集包含接受者為 *T 或 T 的所有方法集

這條規則說的是如果我們用來調用特定接口方法的接口變量是一個指針類型,那么方法的接受者可以是值類型也可以是指針類型。顯然我們的例子不符合該規則,因為我們傳入 SendNotification 函數的接口變量是一個值類型。

1.類型 T 的可調用方法集包含接受者為 T 的所有方法

這條規則說的是如果我們用來調用特定接口方法的接口變量是一個值類型,那么方法的接受者必須也是值類型該方法才可以被調用。顯然我們的例子也不符合這條規則,因為我們 Notify 方法的接受者是一個指針類型。

語言規范里只有這兩條規則,我通過這兩條規則得出了符合我們例子的規則:

1.類型 T 的可調用方法集不包含接受者為 *T 的方法

我們碰巧趕上了我推斷出的這條規則,所以編譯器會報錯。Notify 方法使用指針類型作為接受者而我們卻通過值類型來調用該方法。解決辦法也很簡單,我們只需要傳入 User 值的地址到 SendNotification 函數就好了:

復制代碼 代碼如下:

func main() {
  user := User{
    Name:  "AriesDevil",
    Email: "ariesdevil@xxoo.com",
  }
 
  SendNotification(user)
}

// Output:
User: Sending User Email To AriesDevilariesdevil@xxoo.com>

詳細代碼:http://play.golang.org/p/kEKzyTfLjA

嵌入類型

結構體類型可以包含匿名或者嵌入字段。也叫做嵌入一個類型。當我們嵌入一個類型到結構體中時,該類型的名字充當了嵌入字段的字段名。

下面定義一個新的類型然后把我們的 User 類型嵌入進去:

復制代碼 代碼如下:

type Admin struct {
  User
  Level  string
}

我們定義了一個新類型 Admin 然后把 User 類型嵌入進去,注意這個不叫繼承而叫組合。 User 類型跟 Admin 類型沒有關系。

我們來改變一下 main 函數,創建一個 Admin 類型的變量并把變量的地址傳入 SendNotification 函數中:

復制代碼 代碼如下:

func main() {
  admin := Admin{
    User: User{
      Name:  "AriesDevil",
      Email: "ariesdevil@xxoo.com",
    },
    Level: "master",
  }
 
  SendNotification(admin)
}

// Output
User: Sending User Email To AriesDevilariesdevil@xxoo.com>

詳細代碼:http://play.golang.org/p/ivzzzk78TC

事實證明,我們可以 Admin 類型的一個指針來調用 SendNotification 函數。現在 Admin 類型也通過來自嵌入的 User 類型的方法提升實現了該接口。

如果 Admin 類型包含了 User 類型的字段和方法,那么它們在結構體中的關系是怎么樣的呢?

當我們嵌入一個類型,這個類型的方法就變成了外部類型的方法,但是當它被調用時,方法的接受者是內部類型(嵌入類型),而非外部類型。— Effective Go

因此嵌入類型的名字充當著字段名,同時嵌入類型作為內部類型存在,我們可以使用下面的調用方法:

復制代碼 代碼如下:

admin.User.Notify()

// Output
User: Sending User Email To AriesDevilariesdevil@xxoo.com>

詳細代碼:http://play.golang.org/p/0WL_5Q6mao

這兒我們通過類型名稱來訪問內部類型的字段和方法。然而,這些字段和方法也同樣被提升到了外部類型:

復制代碼 代碼如下:

admin.Notify()

// Output
User: Sending User Email To AriesDevilariesdevil@xxoo.com>

詳細代碼:http://play.golang.org/p/2snaaJojRo

所以通過外部類型來調用 Notify 方法,本質上是內部類型的方法。

下面是 Go 語言中內部類型方法集提升的規則:

給定一個結構體類型 S 和一個命名為 T 的類型,方法提升像下面規定的這樣被包含在結構體方法集中:

1.如果 S 包含一個匿名字段 T,S 和 *S 的方法集都包含接受者為 T 的方法提升。

這條規則說的是當我們嵌入一個類型,嵌入類型的接受者為值類型的方法將被提升,可以被外部類型的值和指針調用。

1.對于 *S 類型的方法集包含接受者為 *T 的方法提升

這條規則說的是當我們嵌入一個類型,可以被外部類型的指針調用的方法集只有嵌入類型的接受者為指針類型的方法集,也就是說,當外部類型使用指針調用內部類型的方法時,只有接受者為指針類型的內部類型方法集將被提升。

1.如果 S 包含一個匿名字段 *T,S 和 *S 的方法集都包含接受者為 T 或者 *T 的方法提升

這條規則說的是當我們嵌入一個類型的指針,嵌入類型的接受者為值類型或指針類型的方法將被提升,可以被外部類型的值或者指針調用。

這就是語言規范里方法提升中僅有的三條規則,我根據這個推導出一條規則:

1.如果 S 包含一個匿名字段 T,S 的方法集不包含接受者為 *T 的方法提升。

這條規則說的是當我們嵌入一個類型,嵌入類型的接受者為指針的方法將不能被外部類型的值訪問。這也是跟我們上面陳述的接口規則一致。

回答開頭的問題

現在我們可以寫程序來回答開頭提出的兩個問題了,首先我們讓 Admin 類型實現 Notifier 接口:

復制代碼 代碼如下:

func (a *Admin) Notify() error {
  log.Printf("Admin: Sending Admin Email To %s%s>\n",
      a.Name,
      a.Email)
     
  return nil
}

Admin 類型實現的接口顯示一條 admin 方面的信息。當我們使用 Admin 類型的指針去調用函數 SendNotification 時,這將幫助我們確定到底是哪個接口實現被調用了。

現在創建一個 Admin 類型的值并把它的地址傳入 SendNotification 函數,來看看發生了什么:

復制代碼 代碼如下:

func main() {
  admin := Admin{
    User: User{
      Name:  "AriesDevil",
      Email: "ariesdevil@xxoo.com",
    },
    Level: "master",
  }
 
  SendNotification(admin)
}

// Output
Admin: Sending Admin Email To AriesDevilariesdevil@xxoo.com>

詳細代碼:http://play.golang.org/p/JGhFaJnGpS

預料之中,Admin 類型的接口實現被 SendNotification 函數調用。現在我們用外部類型來調用 Notify 方法會發生什么呢:

復制代碼 代碼如下:

admin.Notify()

// Output
Admin: Sending Admin Email To AriesDevilariesdevil@xxoo.com>

詳細代碼:http://play.golang.org/p/EGqK6DwBOi

我們得到了 Admin 類型的接口實現的輸出。User 類型的接口實現不被提升到外部類型了。

現在我們有了足夠的依據來回答問題了:

1.編譯器會因為我們同時有兩個接口實現而報錯嗎?

不會,因為當我們使用嵌入類型時,類型名充當了字段名。嵌入類型作為結構體的內部類型包含了自己的字段和方法,且具有唯一的名字。所以我們可以有同一接口的內部實現和外部實現。

1.如果編譯器接受這樣的定義,那么當接口調用時編譯器要怎么確定該使用哪個實現?

如果外部類型包含了符合要求的接口實現,它將會被使用。否則,通過方法提升,任何內部類型的接口實現可以直接被外部類型使用。

總結

在 Go 語言中,方法,接口和嵌入類型一起工作方式是獨一無二的。這些特性可以幫助我們像面向對象那樣組織結構然后達到同樣的目的,并且沒有其它復雜的東西。用本文中談到的語言特色,我們可以以極少的代碼來構建抽象和可伸縮性的框架。

您可能感興趣的文章:
  • Go語言中嵌入C語言的方法
  • golang官方嵌入文件到可執行程序的示例詳解

標簽:楚雄 晉城 運城 湘潭 九江 喀什 深圳 本溪

巨人網絡通訊聲明:本文標題《Go語言中的方法、接口和嵌入類型詳解》,本文關鍵詞  語言,中的,方法,接口,和,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go語言中的方法、接口和嵌入類型詳解》相關的同類信息!
  • 本頁收集關于Go語言中的方法、接口和嵌入類型詳解的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    国产精品久久久久久亚洲色| 欧美日韩高清一区二区| 欧美成人乱码一区二区三区| 午夜视频久久久久久| 日批视频在线看| 欧美在线观看视频一区二区三区| 成人欧美一区二区三区在线播放| 成人午夜私人影院| 2018天天弄| 中文字幕永久在线不卡| 成人激情视频网站| 欧美三级日本三级| 国产精品高清亚洲| 99热在这里有精品免费| 欧美在线观看视频一区二区| 一区二区三区美女视频| 久久久精品人妻一区二区三区| 欧美日韩一区高清| 水蜜桃久久夜色精品一区的特点 | 日韩一级片在线播放| 午夜激情久久久| 免费无码一区二区三区| 欧美r级在线观看| 久久99日本精品| 国产一二三四视频| 18成人在线观看| 年下总裁被打光屁股sp| 日韩一级片在线播放| 经典三级一区二区| 午夜剧场免费在线观看| 亚洲三级在线观看| 国产国语老龄妇女a片| 日韩欧美的一区二区| 国产尤物一区二区| 538精品在线视频| 一区二区三区免费在线观看| 国产a级黄色片| 久久久91精品国产一区二区三区| 国产aⅴ综合色| 欧美主播一区二区三区美女| 天天色天天爱天天射综合| 黄色aaa视频| 国产精品久久久久久久第一福利 | 欧美亚洲禁片免费| 五月婷婷欧美视频| 亚洲一二三精品| 亚洲欧美综合在线精品| 污污免费在线观看| 久久人人超碰精品| 99久久婷婷国产综合精品电影| 欧美精选一区二区| 国产一区免费电影| 欧美系列亚洲系列| 六月丁香综合在线视频| 欧美三级在线免费观看| 日韩影院在线观看| 艳妇荡乳欲伦69影片| 亚洲国产中文字幕在线视频综合| 性欧美13一14内谢| 亚洲免费av高清| b站大片免费直播| 亚洲欧美日韩中文字幕一区二区三区| 超碰caoprom| 国产精品久久久久久久裸模| 午夜免费福利影院| 国产欧美日本一区视频| 亚洲欧美综合视频| 中文字幕欧美日本乱码一线二线| 国产人成视频在线观看| 国产精品二三区| 少妇大叫太粗太大爽一区二区| 亚洲视频一区二区在线观看| 五级黄高潮片90分钟视频| 亚洲日本va午夜在线电影| 日本一级免费视频| 亚洲一区二区在线视频| 三上悠亚在线观看视频| 免费在线观看精品| 欧美色图一区二区三区| 国产九色sp调教91| 欧美精品亚洲二区| 成人av电影免费在线播放| 精品欧美久久久| 少妇熟女视频一区二区三区| 国产欧美一区二区三区在线看蜜臀| 一本色道久久hezyo无码| 国产精品亲子乱子伦xxxx裸| 三上悠亚ssⅰn939无码播放 | 免费人成精品欧美精品| 日本高清无吗v一区| 国产一区二区不卡在线| 日韩欧美国产综合| 麻豆免费在线观看视频| 国产精品国产精品国产专区不蜜 | 亚洲人成影院在线观看| 亚洲一二三精品| 蜜桃传媒麻豆第一区在线观看| 在线观看一区二区视频| 国产91在线|亚洲| 精品久久国产字幕高潮| 亚洲一区和二区| 一区二区视频在线| 小泽玛利亚一区二区免费| 精品综合免费视频观看| 91精品国产色综合久久久蜜香臀| 91视频在线看| 国产精品不卡一区二区三区| 精品在线观看一区| 韩国精品一区二区| 欧美va亚洲va香蕉在线| 少妇一级淫片免费放播放| 一区二区三区四区高清精品免费观看| 永久免费看mv网站入口| 国产中文字幕一区| 欧美精品一区在线观看| 欧美成人午夜精品免费| 奇米色一区二区| 91精品国产综合久久小美女| 美女伦理水蜜桃4| 亚洲成av人影院在线观看网| 欧美影视一区在线| 91色九色蝌蚪| 亚洲男人的天堂在线观看| 色视频成人在线观看免| 99久久精品情趣| 亚洲人成在线观看一区二区| 色婷婷av一区二区三区软件| 99久久er热在这里只有精品15| 亚洲欧洲一区二区三区| 免费三级在线观看| 国产麻豆一精品一av一免费| 精品福利在线导航| 丁香花五月婷婷| 国产一区不卡精品| 国产欧美日韩不卡免费| 欧美黄色aaa| 99久久夜色精品国产网站| 亚洲蜜臀av乱码久久精品 | 91精品福利在线| 99re这里只有精品视频首页| 亚洲男女一区二区三区| 欧美视频在线观看一区| 一级黄色电影片| 免费观看在线综合色| 欧美精品一区男女天堂| 三级黄色在线观看| 99精品偷自拍| 性欧美疯狂xxxxbbbb| 日韩一级在线观看| www久久久久久久| 成人看片黄a免费看在线| 亚洲精品日韩专区silk| 91精品中文字幕一区二区三区| 中国黄色a级片| 国产精品911| 亚洲图片你懂的| 欧美日韩dvd在线观看| 国产麻豆天美果冻无码视频| 久久99久久精品| 日本一区二区高清| 欧美亚洲日本一区| 亚洲久久久久久| 韩国三级在线一区| 综合久久一区二区三区| 欧美日韩在线不卡| 在线不卡av电影| 成人国产精品免费观看动漫| 亚洲综合在线视频| 日韩精品一区二区三区蜜臀| 欧美激情精品久久久久久免费| 男男受被啪到高潮自述| 日本不卡1234视频| 亚洲国产精品ⅴa在线观看| 欧美日韩在线播放一区| 精品欧美一区二区久久久| 99精品欧美一区二区蜜桃免费 | 亚洲精品欧美激情| 91精品国产乱码| 日韩一区二区三区四区视频| 香蕉网在线视频| 男男成人高潮片免费网站| 国产精品乱码一区二三区小蝌蚪| 欧美无人高清视频在线观看| 亚洲欧洲久久久| 97精品国产97久久久久久久久久久久| 日本午夜一区二区| 中文字幕一区二区在线播放| 7777精品伊人久久久大香线蕉超级流畅| 91成人在线免费视频| 97精品久久久午夜一区二区三区| 蜜臀久久久久久久| 亚洲美女视频在线观看| 日韩欧美在线影院| 99热精品免费| 97在线观看免费视频| 人妻换人妻仑乱| 国产一区视频在线看| 亚洲成人精品在线观看| 欧美激情一区二区三区不卡 | 91看片淫黄大片一级在线观看|