溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Golang 結(jié)構(gòu)體與初始化介紹

發(fā)布時間:2020-05-22 17:54:29 來源:億速云 閱讀:247 作者:鴿子 欄目:編程語言

Go 通過類型別名(alias types)和結(jié)構(gòu)體的形式支持用戶自定義類型。

結(jié)構(gòu)體是復(fù)合類型,當需要定義類型,它由一系列屬性組成,每個屬性都有自己的類型和值的時候,就應(yīng)該使用結(jié)構(gòu)體,它把數(shù)據(jù)聚集在一起。

結(jié)構(gòu)體也是值類型,因此可以通過 new 函數(shù)來創(chuàng)建

組成結(jié)構(gòu)體類型的那些數(shù)據(jù)成為字段(fields)。每個字段都有一個類型和一個名字;在一個結(jié)構(gòu)體中,字段名字必須是唯一的。

一,結(jié)構(gòu)體定義

結(jié)構(gòu)體定義的一般方式如下:

type identifier struct {   
   field type1
    field type2}

type T struct {a, b int} 也是合法的語法,它更適用于簡單的結(jié)構(gòu)體

結(jié)構(gòu)體里的字段都有 名字,像 field1、field2 等,如果字段在代碼中從來也不會被用到,那么可以命名它為 _。

結(jié)構(gòu)體類型和字段的命名遵循可見性規(guī)則,所以可能存在一個結(jié)構(gòu)體類型的某些字段是導出的,而另一些沒有導出。

結(jié)構(gòu)體的字段可以是任何類型,甚至是結(jié)構(gòu)體本身,也可以是函數(shù)或者接口??梢月暶鹘Y(jié)構(gòu)體類型的一個變量,然后像下面這樣給它的字段賦值:

var s T
s.a = 5
s.b = 8

數(shù)組也可以看作是一種結(jié)構(gòu)體類型,不過它使用下標而不是具名的字段

二,初始化

方式一:通過 var 聲明結(jié)構(gòu)體

在 Go 語言中當一個變量被聲明的時候,系統(tǒng)會自動初始化它的默認值,比如 int 被初始化為 0,指針為 nil。
var 聲明同樣也會為結(jié)構(gòu)體類型的數(shù)據(jù)分配內(nèi)存,所以我們才能像上一段代碼中那樣,在聲明了 var s T 之后就能直接給他的字段進行賦值

方式二:使用 new

使用 new 函數(shù)給一個新的結(jié)構(gòu)體變量分配內(nèi)存,它返回指向已分配內(nèi)存的指針:var t *T = new(T)。

type struct1 struct {
    i1 int
    f1 float32
    str string}func main() {
    ms := new(struct1)
    ms.i1 = 10
    ms.f1 = 15.5
    ms.str= "Chris"

    fmt.Printf("The int is: %d\n", ms.i1)
    fmt.Printf("The float is: %f\n", ms.f1)
    fmt.Printf("The string is: %s\n", ms.str)
    fmt.Println(ms)
}

與面向?qū)ο笳Z言相同,使用點操作符可以給字段賦值:structname.fieldname = value。

同樣的,使用點操作符可以獲取結(jié)構(gòu)體字段的值:structname.fieldname。

方式三:使用字面量

type Person struct {
    name string
    age int
    address string
}

func main() {
    var p1 Person
    p1 = Person{"lisi", 30, "shanghai"}   //方式A
    p2 := Person{address:"beijing", age:25, name:"wangwu"} //方式B
    p3 := Person{address:"NewYork"} //方式C
}

在(方式A)中,值必須以字段在結(jié)構(gòu)體定義時的順序給出。(方式B)是在值前面加上了字段名和冒號,這種方式下值的順序不必一致,并且某些字段還可以被忽略掉,就想(方式C)那樣。

除了上面這三種方式外,還有一種初始化結(jié)構(gòu)體實體更簡短和常用的方式,如下:

ms := &Person{"name", 20, "bj"}
ms2 := &Person{name:"zhangsan"}

&Person{a, b, c} 是一種簡寫,底層仍會調(diào)用 new(),這里值的順序必須按照字段順序來寫,同樣它也可以使用在值前面加上字段名和冒號的寫法(見上文的方式B,C)。

表達式 new(Type) 和 &Type{} 是等價的。

三,幾種初始化方式之間的區(qū)別

到目前為止,我們已經(jīng)了解了三種初始化結(jié)構(gòu)體的方式:

//第一種,在Go語言中,可以直接以 var 的方式聲明結(jié)構(gòu)體即可完成實例化
var t T
t.a = 1
t.b = 2

//第二種,使用 new() 實例化
t := new(T)

//第三種,使用字面量初始化
t := T{a, b}
t := &T{} //等效于 new(T)

使用 var t T 會給 t 分配內(nèi)存,并零值化內(nèi)存,但是這個時候的 t 的類型是 T

使用 new 關(guān)鍵字時 t := new(T),變量 t 則是一個指向 T 的指針

從內(nèi)存布局上來看,我們就能看出這三種初始化方式的區(qū)別:

使用 var 聲明:

Golang 結(jié)構(gòu)體與初始化介紹

使用 new 初始化:

Golang 結(jié)構(gòu)體與初始化介紹

使用結(jié)構(gòu)體字面量初始化:

Golang 結(jié)構(gòu)體與初始化介紹

下面來看一個具體的例子:

package main
import "fmt"

type Person struct {
 name string
 age int
}

func main() {
 var p1 Person
 p1.name = "zhangsan"
 p1.age = 18
 fmt.Printf("This is %s, %d years old\n", p1.name, p1.age)

 p2 := new(Person)
 p2.name = "lisi"
 p2.age = 20
 (*p2).age = 23 //這種寫法也是合法的
 fmt.Printf("This is %s, %d years old\n", p2.name, p2.age)

 p3 := Person{"wangwu", 25}
 fmt.Printf("This is %s, %d years old\n", p3.name, p3.age)
}

輸出:

This is zhangsan, 18 years old
This is lisi, 23 years old
This is wangwu, 25 years old

上面例子的第二種情況,雖然 p2 是指針類型,但我們?nèi)匀豢梢韵?p2.age = 23 這樣賦值,不需要像 C++ 中那樣使用 -> 操作符,Go 會自動進行轉(zhuǎn)換。

注意也可以先通過 * 操作符來獲取指針所指向的內(nèi)容,再進行賦值:(*p2).age = 23。

結(jié)構(gòu)體的內(nèi)存布局

Go 語言中,結(jié)構(gòu)體和它所包含的數(shù)據(jù)在內(nèi)存中是以連續(xù)塊的形式存在的,即使結(jié)構(gòu)體中嵌套有其他的結(jié)構(gòu)體,這在性能上帶來了很大的優(yōu)勢。不像 Java 中的引用類型,一個對象和它里面包含的對象可能會在不同的內(nèi)存空間中,這點和 Go 語言中的指針很像。

下面的例子清晰地說明了這些情況:

type Rect1 struct {Min, Max Point }
type Rect2 struct {Min, Max *Point }

Golang 結(jié)構(gòu)體與初始化介紹

以上就是Go語言結(jié)構(gòu)體與初始化圖文詳解的詳細內(nèi)容,更多請關(guān)注億速云其它相關(guān)文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI