結構體定義的是數據,與C語言的結構體相同。git
結構體定義以下:github
type structTypeName struct { member definition; member definition; ... member definition; }
結構體變量能夠有兩種聲明方式(使用KV方式時,能夠僅初始化部分紅員):函數
varName := structTypeName {value1, value2...valuen} varName := structTypeName { key1: value1, key2: value2..., keyn: valuen}
還有另一種,經過new
來建立特定對象:測試
varName := new (structTypeName) // 使用默認值初始化
代碼範例:spa
type student struct { name string age int grage int } func main() { s1 := student{"wang", 10, 2} s2 := new(student) // s3 := make(student) // cannot make type student s2.name = "li"; s2.age = 11; fmt.Println(s1) fmt.Println(s2) }
內嵌結構體是指將某個結構體,潛入到其餘的結構體中,相似於C語言中的struct內部定義struct。
Go語言中不能在struct內部嵌套,而是須要將內嵌的結構體獨立聲明。指針
範例,咱們須要在student
結構體中內嵌other
結構體:code
type other struct { // 聲明other結構體 addr string } type student struct { name string age int grage int other // 內嵌other結構體 }
若是名字沒有衝突,能夠直接使用內嵌結構體的字段對象
s1 := student{"wang", 10, 2, other{"JS"}} // 初始化時須要帶着內嵌結構體一塊兒 s1.addr = "JJ" // 直接使用內嵌結構體的成員變量名 s1.other.addr = "AA" // 訪問特定類型的內嵌結構體成員變量名,名字衝突時使用
這裏順便將內嵌
與組合
區分下,若是使用組合方式,則student
的定義將會相似以下:繼承
type student struct { name string age int grage int etc other // 組合other對象 }
在 Go 語言中,結構體與C語言的結構體等價,表示純數據,那麼Go是否支持面向對象呢?如何實如今結構體上實現方法呢?接口
實際上,Go的方法
是做用在接收者
上的一個函數,接收者是某種特定類型的變量,因此咱們能夠人爲方法
是一種特殊類型的函數,Go的這種綁定與Lisp語言很是類似。
Go中方法接收者
類型幾乎能夠是任何類型,任何類型均可以有方法,甚至能夠是函數類型。接收者不能是如下類型:
類型+方法構成了傳統面嚮對象語言中的一個類
,在 Go 中,類型的代碼和綁定在它上面的方法的代碼必須位於同一個包中,但能夠存在於不一樣的源文件中(這個也就限制了您不能給int
類型增長方法)。
Go語言中不支持方法重載
,即對於一個類型只能有一個給定名稱的方法,可是具備一樣名字的方法能夠在 2 個或多個不一樣的接收者類型上存在。
方法定義:
func (recv receiverType) methodName(paraList) (returnValueList) { ... }
範例:
func (a *denseMatrix) Add(b Matrix) Matrix func (a *sparseMatrix) Add(b Matrix) Matrix
上文說起到,方法是一種特殊的函數,實際上咱們能夠人爲僅僅是格式有差別。
例如對於變量rcv
:
FuncCall(recv)
;rcv.Method()
。Go的這種方法與結構獨立的方式,很好的解決了耦合問題。
以值爲接收者時,調用方法時會將接收者的值傳遞進去,因此在方法內部修改接收者時,實際上修改的時傳遞進來的接收者副本,並不會影響接收者自己。
以指針爲接收者時,在方法內部修改接收者數據時,直接做用在接收者上。
之前面的student
爲例,追加2個方法:
func (s *student) funcPtr() { s.name = "ptrName" fmt.Printf("funcPtr: Change student name to ptrName\n") } func (s student) funcObj() { s.name = "objName" fmt.Printf("funcObj: Change student name to objName\n") }
測試代碼:
s1 := student{"wang", 10, 2, other{"JS"}} s1.funcObj() fmt.Println(s1) s1.funcPtr() fmt.Println(s1)
輸出結果:
funcObj: Change student name to objName {wang 10 2 {JS}} funcPtr: Change student name to ptrName {ptrName 10 2 {JS}}
結論:使用指針方式傳遞時,能夠修改接收者的數據。
內嵌類型的綁定方法後,外層結構至關於自動擁有了該方法。
範例,內嵌類型Point
綁定了Abs
方法,此時NamedPoint
類型將自動擁有該方法:
type Point struct { x, y float64 } func (p *Point) Abs() float64 { return math.Sqrt(p.x*p.x + p.y*p.y) } type NamedPoint struct { Point name string }
測試代碼:
n := NamedPoint{Point{3, 4}, "Pythagoras"} fmt.Println(n.Abs()) // 輸出「5」
若是您在外層類中實現了同名方法,那麼外層類型的方法將覆蓋內層類型的方法。
若是一個類型包含了多個子類型,就至關於該類型繼承了多個子類型的方法,等同於C++中的多重繼承。
Go語言約定以下方法調用規則:
也就是,方法應綁定到*T
的類型上。
參考書籍:https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md