我的 github:github.com/iswbm/golangcodingtime
在之前學過的資料型別中,陣列與切片,只能儲存同一型別的變數。若要儲存多個型別的變數,就需要用到結構體,它是將多個容易型別的命令變數組合在一起的聚合資料型別。
每個變數都成為該結構體的成員變數。
可以理解為 go語言 的結構體struct和其他語言的class有相等的地位,但是go語言放棄大量物件導向的特性,所有的go語言型別除了指標型別外,都可以有自己的方法,提高了可擴充套件性。
宣告結構體
type 結構體名 struct
比如我要定義乙個可以儲存個人資料名為 profile 的結構體,可以這麼寫
type profile struct
在 go 語言中,我們無法在結構體內定義方法,那如何給乙個結構體定義方法呢,答案是可以使用組合函式的方式來定義結構體方法。它和普通函式的定義方式有些不一樣,比如下面這個方法
func (person profile) fmtprofile()
其中fmt_profile
是方法名,而(person profile)
:表示將 fmt_profile 方法與 profile 的例項繫結。我們把 profile 稱為方法的接收者,而 person 表示例項本身,它相當於 python 中的 self,在方法內可以使用person.屬性名
的方法來訪問例項屬性。
完整**如下:
package main
import "fmt"
// 定義乙個名為profile 的結構體
type profile struct
// 定義乙個與 profile 的繫結的方法
func (person profile) fmtprofile()
func main()
// 呼叫函式
myself.fmtprofile()
}
輸出如下
名字:小明
年齡:24
性別:male
上面定義方法的方式叫當你想要在方法內改變例項的屬性的時候,必須使用指標做為方法的接收者。
package main
import "fmt"
// 宣告乙個 profile 的結構體
type profile struct
// 重點在於這個星號: *
func (person *profile) increase_age()
func main()
fmt.printf("當前年齡:%d\n", myself.age)
myself.increase_age()
fmt.printf("當前年齡:%d", myself.age)
}
輸出結果 如下,可以看到在方法內部對 age 的修改已經生效。你可以嘗試去掉*
,使用值做為方法接收者,看看age是否會發生改變。
當前年齡:24
當前年齡:25
至此,我們知道了兩種定義方法的方式:
那我們如何進行選擇呢?以下幾種情況,應當直接使用指標做為方法的接收者。
你需要在方法內部改變結構體內容的時候
出於效能的問題,當結構體過大的時候
有些情況下,以值或指標做為接收者都可以,但是考慮到**一致性,建議都使用指標做為接收者。
不管你使用哪種方法定義方法,指標例項物件、值例項物件都可以直接呼叫,而沒有什麼約束。這一點go語言做得非常好。
為什麼標題的繼承,加了雙引號,因為go 語言本身並不支援繼承。
但我們可以使用組合的方法,實現類似繼承的效果。
在生活中,組合的例子非常多,比如一台電腦,是由機身外殼,主機板,cpu,記憶體等零部件組合在一起,最後才有了我們用的電腦。
同樣的,在 go 語言中,把乙個結構體嵌入到另乙個結構體的方法,稱之為組合。
現在這裡有乙個表示公司(company)的結構體,還有乙個表示公司職員(staff)的結構體。
type company struct
type staff struct
若要將公司資訊與公司職員關聯起來,一般都會想到將 company 結構體的內容照抄到 staff 裡。
type staff struct
雖然在實現上並沒有什麼問題,但在你對同一公司的多個staff初始化的時候,都得重複初始化相同的公司資訊,這做得並不好,借鑑繼承的思想,我們可以將公司的屬性都「繼承」過來。
但是在 go 中沒有類的概念,只有組合,你可以將 company 這個 結構體嵌入到 staff 中,做為 staff 的乙個匿名字段,staff 就直接擁有了 company 的所有屬性了。
type staff struct
來寫個完整的程式驗證一下。
package main
import "fmt"
type company struct
type staff struct
func main()
staffinfo := staff
fmt.printf("%s 在 %s 工作\n", staffinfo.name, staffinfo.companyname)
fmt.printf("%s 在 %s 工作\n", staffinfo.name, staffinfo.company.companyname)
}
輸出結果如下,可見staffinfo.companyname
和staffinfo.company.companyname
的效果是一樣的。
小明 在 tencent 工作
小明 在 tencent 工作
在 go 語言中,函式名的首字母大小寫非常重要,它被來實現控制對方法的訪問許可權。
01. 開發環境的搭建(goland & vs code)
02. 學習五種變數建立的方法
03. 詳解資料型別:****整形與浮點型
04. 詳解資料型別:byte、rune與string
05. 詳解資料型別:陣列與切片
06. 詳解資料型別:字典與布林型別
07. 詳解資料型別:指標
08. 物件導向程式設計:結構體與繼承
09. 一篇文章理解 go 裡的函式
10. go語言流程控制:if-else 條件語句
11. go語言流程控制:switch-case 選擇語句
12. go語言流程控制:for 迴圈語句
13. go語言流程控制:goto 無條件跳轉
14. go語言流程控制:defer 延遲呼叫
15. 物件導向程式設計:介面與多型
16. 關鍵字:make 和 new 的區別?
17. 一篇文章理解 go 裡的語句塊與作用域
18. 學習 go 協程:goroutine
19. 學習 go 協程:詳解通道/通道
20. 幾個通道死鎖經典錯誤案例詳解
21. 學習 go 協程:waitgroup
22. 學習 go 協程:互斥鎖和讀寫鎖
23. go 裡的異常處理:panic 和 recover
24. 超詳細解讀 go modules 前世今生及入門使用
25. go 語言中關於包匯入必學的 8 個知識點
26. 如何開源自己寫的模組給別人用?
27. 說說 go 語言中的型別斷言?
28. 這五點帶你理解go語言的select用法
Go語言 物件導向程式設計
go語言的語言設計非常的簡潔,因為,go語言並沒有物件導向的概念,因此go語言中沒有物件導向的一些概念,例如 封裝 繼承 多型,虛函式 建構函式,this指標等 儘管go語言中沒有封裝 繼承 多型,但同樣也可以實現相應的功能。封裝 通過方法進行實現 繼承 通過匿名字段實現 多型 通過介面實現 方法也...
Go 物件導向程式設計
值語義與引用語義的區別在於賦值。值型別不會改變變數值,引用型別會改變變數值。go 語言中大多數型別都是基於值語義,包括 基本型別 如byte int bool float32 float64和string 復合型別 如陣列 array 結構體 struct 和指標 pointer 等。go語言中的陣...
go語言物件導向
go語言可通過struct宣告新的型別 新建乙個型別person type person struct var p1 person p1.name liming p1.age 18新建乙個型別student,可以通過匿名欄位將person所有欄位隱式引入student type student st...