玩轉Golang之Struct結構體

來源:互聯網
上載者:User

先介紹一下go語言的類型系統

Golang中的類型系統

類型系統是指一個語言的類型體繫結構。一個典型的類型系統通常包含如下基本內容:

基礎類型,如byte、int、bool、float等;
複合類型,如數組、結構體、指標等;
可以指向任意對象的類型(Any類型);
值語義和引用語義;
物件導向,即所有具備物件導向特徵(比如成員方法)的類型;
介面。

Go語言中的大多數類型都是值語義,並且都可以包含對應的操作方法。在需要的時候,你可以給任何類型(包括內建類型)“增加”新方法。而在實現某個介面時,無需從 該介面繼承(事實上,Go語言根本就不支援物件導向思想中的繼承文法),只需要實現該介面 要求的所有方法即可。任何類型都可以被Any類型引用。Any類型就是空介面,即interface{}。

什麼是結構體

結構體(struct)是使用者自訂的類型,它代表若干欄位的集合,可以用於描述一個實體物件,類似java中的class,是golang物件導向編程的基礎類型。
結構體的概念在軟體工程上舊的術語叫 ADT(抽象資料類型:Abstract Data Type)。在 C++ 它也存在,並且名字也是 struct,在物件導向的程式設計語言中,跟一個無方法的輕量級類一樣。因為 Go 語言中沒有類的概念,所以在 Go 中結構體有著更為重要的地位。

如何定義一個結構體

type Coordinate struct {    X, Y float32}

文法:type<Name>struct{}
上述代碼定義個一個名為Coordinate的結構體,裡麵包括了兩個float32的變數X,Y,該結構體可用於表示一個平面座標。

添加對象方法

其他的經典物件導向語言,如java,C#,定義對象方法時,會包含在class的定義內,如

public class Coordinate{    public float X {get; set;}    public float Y {get; set;}    //列印座標    public void GetCoordinate(){          Console.WriteLine("("+this.X+","+this.Y+")");    }}

在go語言中,對象方法在結構體定義的外部添加

type Coordinate struct {    X, Y float32}//列印座標func (coo *Coordinate) GetCoordinate() {    fmt.Printf("(%.2f,%.2f)\n", coo.X, coo.Y)    return}

其中,func關鍵字後面的(coo *Coordinate),表示該函數傳入一個指向Coordinate的指標,可通過指標變數coo來操作結構體的值。

幾種結構體初始化

一、按原始欄位順序通過建立結構體

package mainimport (    "fmt")func main(){    p0 := Coordinate{1, 2}    p0.GetCoordinate()}

輸出:(1.00,2.00),其中X=1,Y=2

二、按照自訂欄位順序進行初始化

package mainimport (    "fmt")func main(){    p0 := Coordinate{Y:1, X:2}    p0.GetCoordinate()}

輸出:(2.00,1.00),其中X=2,Y=1

三、通過new函數建立

package mainimport (    "fmt")func main(){    //給該結構體p2變數分配記憶體,它返回指向已指派記憶體的指標    p0 := new(Coordinate)    p0.X=1    p0.Y=2    p0.GetCoordinate()}

輸出:(1.00,2.00),其中X=1,Y=2
其中p0 := new(Coordinate)等價於以下寫法

p3 := &Coordinate{X: 1, Y: 2}
p3 := &Coordinate{1,2}

比較三種建立方式

其中,第一種與第二種,p0均為一個類型為Coordinate的執行個體,而第三種p0為一個指向Coordinate的指標,相當於var p0 *Coordinate = new(Coordinate)

一般在進行例如type T struct {a, b int}的結構體定義之後
習慣使用t := new(T)給該結構體變數分配記憶體,它返回指向已指派記憶體的指標。變數t是一個指向T的指標,此時結構體欄位的值是它們所屬類型的零值。
聲明 var t T 也會給 t 分配記憶體,並零值化記憶體,但是這個時候 t是類型T。在這兩種方式中,t 通常被稱做類型T的一個執行個體(instance)或對象(Object)var t *T = new(T)等價於t := new(T)

通過程式碼分析以上結論

package mainimport (    "fmt")func main(){    p0 := Coordinate{1, 2}    //給該結構體p2變數分配記憶體,它返回指向已指派記憶體的指標    p2 := new(Coordinate)    p2.X = 1    p2.Y = 2    p3 := &Coordinate{X: 1, Y: 2}    p4 := &Coordinate{1, 2}    fmt.Println("-------輸出p0-------")    fmt.Printf("%v\n%T\n", p0, p0)    fmt.Println("-------輸出p2-------")    fmt.Printf("%v\n%T\n", p2, p2)    fmt.Println("-------輸出p3-------")    fmt.Printf("%v\n%T\n", p3, p3)    fmt.Println("-------輸出p4-------")    fmt.Printf("%v\n%T\n", p4, p4)}

輸出:

-------輸出p0-------{1 2}Coordinate-------輸出p2-------&{1 2}*Coordinate-------輸出p3-------&{1 2}*Coordinate-------輸出p4-------&{1 2}*Coordinate

可以看出來,p2,p3,p4均為一個指標變數

添加值拷貝的對象方法

剛才說到了,添加一個對象方法,可以通過func (t *T) functionname()來建立,其中t為一個指標變數。我們也可以通過值拷貝的方式,添加一個對象方法,文法為func(t T) functionname()

package mainimport (    "fmt")type Coordinate struct {    X, Y float32}func (coo *Coordinate) GetCoordinate() {    fmt.Printf("(%.2f,%.2f)\n", coo.X, coo.Y)    return}//值拷貝對象方法func (coo Coordinate) SetPosition01(a float32,b float32) {    coo.X = a    coo.Y = b}//指標變數對象方法func (coo *Coordinate) SetPosition02(a float32,b float32) {    coo.X = a    coo.Y = b}func main(){    p0 := Coordinate{1, 2}    fmt.Print("SetPosition02調用前:")    p0.GetCoordinate()    p0.SetPosition02(0, 0)    fmt.Print("SetPosition02調用後:")    p0.GetCoordinate()}

輸出:

SetPosition01調用前:(1.00,2.00)SetPosition01調用後:(1.00,2.00)SetPosition02調用前:(1.00,2.00)SetPosition02調用後:(0.00,0.00)

從程式輸出中可以看出,調用SetPosition01方法,發生了值拷貝,即使在方法內改變了coo的值,外部的p0的值沒有被改變。而SetPosition02方法中,coo為指向p0地址的指標,由於是通過指標變數修改了X,Y的值,所以調用完畢後,外部p0的值會被修改為(0,0)

匿名結構體

package mainimport (    "fmt")func main(){    p_3d := struct {        X, Y, Z float32    }{1, 2, 3}    fmt.Println("-------輸出p_3d-------")    fmt.Printf("%v\n%T\n", p_3d, p_3d)}

輸出:

-------輸出p_3d-------{1 2 3}struct { X float32; Y float32; Z float32 }

p_3d為一個包含X,Y,Z三個變數的匿名結構體

golang建構函式?

在Go語言中沒有建構函式的概念,對象的建立通常交由一個全域的建立函數來完成,以 NewXXX來命名,表示“建構函式”:
這一切非常自然,開發人員也不需要分析在使用了new之後到底背後發生了多少事情。在Go語言中,一切要發生的事情都直接可以看到。
—— 《Go語言編程》

func NewRect(x, y, width, height float64) *Rect {     return &Rect{x, y, width, height}}

變數、方法可見度

Go語言對關鍵字的增加非常吝嗇,其中沒有privateprotectedpublic這樣的關鍵 字。要使某個符號對其他包(package)可見(即可以訪問),需要將該符號定義為以大寫字母開頭,如:

 type Rect struct {   X, Y float64  Width, Height float64 }

這樣,Rect類型的成員變數就全部被匯出了,可以被所有其他引用了Rect所在包的代碼訪問到。 成員方法的可訪問性遵循同樣的規則,例如:

func (r *Rect) area() float64 {     return r.Width * r.Height} 

這樣,Rectarea()方法只能在該類型所在的包內使用。
需要注意的一點是,Go語言中符號的可訪問性是包一級的而不是類型一級的。在上面的例 子中,儘管area()Rect的內部方法,但同一個包中的其他類型也都可以訪問到它。這樣的可訪問性控制很粗曠,很特別,但是非常實用。如果Go語言符號的可訪問性是類型一級的,少不 了還要加上friend這樣的關鍵字,以表示兩個類是朋友關係,可以訪問彼此的私人成員。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.