Golang通脈之結(jié)構(gòu)體

Go語言中的基礎(chǔ)數(shù)據(jù)類型可以表示一些事物的基本屬性,但是要表達(dá)一個(gè)事物的全部或部分屬性時(shí),這時(shí)候再用單一的基本數(shù)據(jù)類型明顯就無法滿足需求了,Go語言提供了一種自定義數(shù)據(jù)類型,可以封裝多個(gè)基本數(shù)據(jù)類型,這種數(shù)據(jù)類型叫結(jié)構(gòu)體,英文名稱struct。 也就是可以通過struct來定義自己的類型了。

Go語言中通過struct來實(shí)現(xiàn)面向?qū)ο蟆?/p>

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

Go 語言中數(shù)組可以存儲(chǔ)同一類型的數(shù)據(jù),但在結(jié)構(gòu)體中我們可以為不同項(xiàng)定義不同的數(shù)據(jù)類型。 結(jié)構(gòu)體是由一系列具有相同類型或不同類型的數(shù)據(jù)構(gòu)成的數(shù)據(jù)集合。

使用typestruct關(guān)鍵字來定義結(jié)構(gòu)體,具體代碼格式如下:

type struct_variable_type struct {
   member definition;
   member definition;
   ...
   member definition;
}

其中:

  • struct_variable_type:標(biāo)識(shí)自定義結(jié)構(gòu)體的名稱,在同一個(gè)包內(nèi)不能重復(fù)。
  • member:表示結(jié)構(gòu)體字段名。結(jié)構(gòu)體中的字段名必須唯一。
  • definition:表示結(jié)構(gòu)體字段的具體類型。

定義一個(gè)Person結(jié)構(gòu)體:

type person struct {
    name string
    city string
    age  int8
}

同樣類型的字段可以寫在一行,

type person1 struct {
    name, city string
    age        int8
}

這樣就擁有了一個(gè)person的自定義類型,它有name、cityage三個(gè)字段。使用這個(gè)person結(jié)構(gòu)體就能夠很方便的在程序中表示和存儲(chǔ)人的信息了。

語言內(nèi)置的基礎(chǔ)數(shù)據(jù)類型是用來描述一個(gè)值的,而結(jié)構(gòu)體是用來描述一組值的。比如一個(gè)人有名字、年齡和居住城市等,本質(zhì)上是一種聚合型的數(shù)據(jù)類型

結(jié)構(gòu)體實(shí)例化

只有當(dāng)結(jié)構(gòu)體實(shí)例化時(shí),即結(jié)構(gòu)體聲明后,才會(huì)真正地分配內(nèi)存。也就是必須實(shí)例化后才能使用結(jié)構(gòu)體的字段。

結(jié)構(gòu)體本身也是一種類型,可以像聲明內(nèi)置類型一樣使用var關(guān)鍵字聲明結(jié)構(gòu)體類型。

var 結(jié)構(gòu)體實(shí)例 結(jié)構(gòu)體類型

基本實(shí)例化

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
    var book1 Books        /* 聲明 book1 為 Books 類型 */
    /* book 1 描述 */
   Book1.title = "Go 語言"
   Book1.author = "Go大佬"
   Book1.subject = "Go"
   Book1.book_id = 6495407
}

通過.來訪問結(jié)構(gòu)體的字段(成員變量)。

匿名結(jié)構(gòu)體

在定義一些臨時(shí)數(shù)據(jù)結(jié)構(gòu)等場(chǎng)景下還可以使用匿名結(jié)構(gòu)體。

func main() {
    var user struct{Name string; Age int}
    user.Name = "張三"
    user.Age = 20
    fmt.Printf("%#v\n", user)
}

創(chuàng)建指針類型結(jié)構(gòu)體

還可以通過使用new關(guān)鍵字對(duì)結(jié)構(gòu)體進(jìn)行實(shí)例化,得到的是結(jié)構(gòu)體的地址:

var p = new(person)
fmt.Printf("%T\n", p)     //*main.person
fmt.Printf("p=%#v\n", p) //p=&main.person{name:"", city:"", age:0}

可以看出p是一個(gè)結(jié)構(gòu)體指針。

需要注意的是在Go語言中支持對(duì)結(jié)構(gòu)體指針直接使用.來訪問結(jié)構(gòu)體的成員。

var p = new(person)
p.name = "張三"
p.age = 18
p.city = "深圳"
fmt.Printf("p=%#v\n", p) //p=&main.person{name:"張三", city:"深圳", age:18}

取結(jié)構(gòu)體的地址實(shí)例化

使用&對(duì)結(jié)構(gòu)體進(jìn)行取地址操作相當(dāng)于對(duì)該結(jié)構(gòu)體類型進(jìn)行了一次new實(shí)例化操作。

book := &Books{}
book.title = "Java"
book.author = "Java大佬"
book.subject = "Java 語言"
book.book_id = 6495700

book.title= "Java"其實(shí)在底層是(*book).title= "Java",這是Go語言實(shí)現(xiàn)的語法糖。

結(jié)構(gòu)體初始化

沒有初始化的結(jié)構(gòu)體,其成員變量都是對(duì)應(yīng)其類型的零值。

type person struct {
    name string
    city string
    age  int8
}

func main() {
    var p person
    fmt.Printf("p=%#v\n", p) //p=main.person{name:"", city:"", age:0}
}

使用鍵值對(duì)初始化

使用鍵值對(duì)對(duì)結(jié)構(gòu)體進(jìn)行初始化時(shí),鍵對(duì)應(yīng)結(jié)構(gòu)體的字段,值對(duì)應(yīng)該字段的初始值。

p := person{
    name: "張三",
    city: "",
    age:  18,
}
fmt.Printf("p=%#v\n", p) //p=main.person{name:"張三", city:"深圳", age:18}

也可以對(duì)結(jié)構(gòu)體指針進(jìn)行鍵值對(duì)初始化,例如:

p := &person{
    name: "張三",
    city: "深圳",
    age:  18,
}
fmt.Printf("p=%#v\n", p) //p=&main.person{name:"張三", city:"深圳", age:18}

當(dāng)某些字段沒有初始值的時(shí)候,該字段可以不寫。此時(shí),沒有指定初始值的字段的值就是該字段類型的零值。

p := &person{
    city: "深圳",
}
fmt.Printf("p=%#v\n", p) //p=&main.person{name:"", city:"深圳", age:0}

使用值的列表初始化

初始化結(jié)構(gòu)體的時(shí)候可以簡寫,也就是初始化的時(shí)候不寫鍵,直接寫值:

p := &person{
    "張三",
    "深圳",
    18,
}
fmt.Printf("p=%#v\n", p) //p=&main.person{name:"張三", city:"深圳", age:18}

使用這種格式初始化時(shí),需要注意:

  1. 必須初始化結(jié)構(gòu)體的所有字段。
  2. 初始值的填充順序必須與字段在結(jié)構(gòu)體中的聲明順序一致。
  3. 該方式不能和鍵值初始化方式混用。

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

結(jié)構(gòu)體占用一塊連續(xù)的內(nèi)存。

type test struct {
    a int8
    b int8
    c int8
    d int8
}
n := test{
    1, 2, 3, 4,
}
fmt.Printf("n.a %p\n", &n.a)
fmt.Printf("n.b %p\n", &n.b)
fmt.Printf("n.c %p\n", &n.c)
fmt.Printf("n.d %p\n", &n.d)

輸出:

n.a 0xc0000a0060
n.b 0xc0000a0061
n.c 0xc0000a0062
n.d 0xc0000a0063

關(guān)于Go語言中的內(nèi)存對(duì)齊:在 Go 中恰到好處的內(nèi)存對(duì)齊

空結(jié)構(gòu)體

空結(jié)構(gòu)體是不占用空間的。

var v struct{}
fmt.Println(unsafe.Sizeof(v))  // 0

空結(jié)構(gòu)體的作用

因?yàn)榭战Y(jié)構(gòu)體不占據(jù)內(nèi)存空間,因此被廣泛作為各種場(chǎng)景下的占位符使用。一是節(jié)省資源,二是空結(jié)構(gòu)體本身就具備很強(qiáng)的語義,即這里不需要任何值,僅作為占位符。

實(shí)現(xiàn)集合(Set)

Go 語言標(biāo)準(zhǔn)庫沒有提供 Set 的實(shí)現(xiàn),通常使用 map 來代替。事實(shí)上,對(duì)于集合來說,只需要 map 的鍵,而不需要值。即使是將值設(shè)置為 bool 類型,也會(huì)多占據(jù) 1 個(gè)字節(jié),那假設(shè) map 中有一百萬條數(shù)據(jù),就會(huì)浪費(fèi) 1MB 的空間。

因此,將 map 作為集合(Set)使用時(shí),可以將值類型定義為空結(jié)構(gòu)體,僅作為占位符使用即可。

type Set map[string]struct{}

func (s Set) Has(key string) bool {
    _, ok := s[key]
    return ok
}

func (s Set) Add(key string) {
    s[key] = struct{}{}
}

func (s Set) Delete(key string) {
    delete(s, key)
}

func main() {
    s := make(Set)
    s.Add("Tom")
    s.Add("Sam")
    fmt.Println(s.Has("Tom"))
    fmt.Println(s.Has("Jack"))
}

不發(fā)送數(shù)據(jù)的信道(channel)

func worker(ch chan struct{}) {
    <-ch
    fmt.Println("do something")
    close(ch)
}

func main() {
    ch := make(chan struct{})
    go worker(ch)
    ch <- struct{}{}
}

有時(shí)候使用 channel 不需要發(fā)送任何的數(shù)據(jù),只用來通知子協(xié)程(goroutine)執(zhí)行任務(wù),或只用來控制協(xié)程并發(fā)度。這種情況下,使用空結(jié)構(gòu)體作為占位符就非常合適了。

僅包含方法的結(jié)構(gòu)體

type Door struct{}

func (d Door) Open() {
    fmt.Println("Open the door")
}

func (d Door) Close() {
    fmt.Println("Close the door")
}

在部分場(chǎng)景下,結(jié)構(gòu)體只包含方法,不包含任何的字段。例如上面的 Door,在這種情況下,Door 事實(shí)上可以用任何的數(shù)據(jù)結(jié)構(gòu)替代:

type Door int
type Door bool

無論是 int 還是 bool 都會(huì)浪費(fèi)額外的內(nèi)存,因此這種情況下,聲明為空結(jié)構(gòu)體是最合適的。

面試題

type student struct {
    name string
    age  int
}

func main() {
    m := make(map[string]*student)
    stus := []student{
        {name: "張三", age: 18},
        {name: "李四", age: 23},
        {name: "王五", age: 25},
    }

    for _, stu := range stus {
        m[stu.name] = &stu
    }
    for k, v := range m {
        fmt.Println(k, "=>", v.name)
    }
}

//與Java的foreach一樣,for range使用的是副本的方式。
//for range在循環(huán)時(shí),go會(huì)創(chuàng)建一個(gè)額外的變量去存儲(chǔ)循環(huán)的元素,所以在每一次迭代中,該變量都會(huì)被重新賦值,
//所以m[stu.Name]=&stu實(shí)際上一致指向同一個(gè)指針, 
//最終該指針的值為遍歷的最后一個(gè)struct的值拷貝。 就像想修改切片元素的屬性:

//for _, stu := range stus {
//  stu.age = stu.age+10
//}

//也是不可行的。

構(gòu)造函數(shù)

Go語言的結(jié)構(gòu)體沒有構(gòu)造函數(shù),但可以自己實(shí)現(xiàn)。 因?yàn)?code>struct是值類型,如果結(jié)構(gòu)體比較復(fù)雜的話,值拷貝性能開銷會(huì)比較大,所以構(gòu)造函數(shù)返回的是結(jié)構(gòu)體指針類型:

func NewPerson(name, city string, age int8) *person {
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}

調(diào)用構(gòu)造函數(shù)

p := NewPerson("張三", "深圳", 18)
fmt.Printf("%#v\n", p) //&main.person{name:"張三", city:"深圳", age:18}

結(jié)構(gòu)體的匿名字段

可以用字段來創(chuàng)建結(jié)構(gòu),這些字段只包含一個(gè)沒有字段名的類型。這些字段被稱為匿名字段。

在類型中,使用不寫字段名的方式,使用另一個(gè)類型

type Human struct {
    name string
    age int
    weight int
} 
type Student struct {
    Human // 匿名字段,那么默認(rèn)Student就包含了Human的所有字段
    speciality string
} 
func main() {
    // 初始化一個(gè)學(xué)生
    mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
    // 訪問相應(yīng)的字段
    fmt.Println("His name is ", mark.name)
    fmt.Println("His age is ", mark.age)
    fmt.Println("His weight is ", mark.weight)
    fmt.Println("His speciality is ", mark.speciality)
    // 修改對(duì)應(yīng)的備注信息
    mark.speciality = "AI"
    fmt.Println("Mark changed his speciality")
    fmt.Println("His speciality is ", mark.speciality)
    // 修改年齡信息
    fmt.Println("Mark become old")
    mark.age = 46
    fmt.Println("His age is", mark.age)
    // 修改體重信息
    fmt.Println("Mark is not an athlet anymore")
    mark.weight += 60
    fmt.Println("His weight is", mark.weight)
}

可以使用"."的方式進(jìn)行調(diào)用匿名字段中的屬性值
實(shí)際就是字段的繼承
其中可以將匿名字段理解為字段名和字段類型都是同一個(gè)
基于上面的理解,所以可以mark.Human = Human{"Marcus", 55, 220}mark.Human.age -= 1
若存在匿名字段中的字段與非匿名字段名字相同,則最外層的優(yōu)先訪問,就近原則
通過匿名訪問和修改字段相當(dāng)?shù)挠杏?,但是不僅僅是struct字段,所有的內(nèi)置類型和自定義類型都是可以作為匿名字段的。

注意:這里匿名字段的說法并不代表沒有字段名,而是默認(rèn)會(huì)采用類型名作為字段名,結(jié)構(gòu)體要求字段名稱必須唯一,因此一個(gè)結(jié)構(gòu)體中同種類型的匿名字段只能有一個(gè)。

嵌套結(jié)構(gòu)體

一個(gè)結(jié)構(gòu)體中可以嵌套包含另一個(gè)結(jié)構(gòu)體或結(jié)構(gòu)體指針。

type Address struct {  
    city, state string
}
type Person struct {  
    name string
    age int
    address Address
}

func main() {  
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.address = Address {
        city: "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:",p.age)
    fmt.Println("City:",p.address.city)
    fmt.Println("State:",p.address.state)
}

提升字段

在結(jié)構(gòu)體中屬于匿名結(jié)構(gòu)體的字段稱為提升字段,因?yàn)樗鼈兛梢员辉L問,就好像它們屬于擁有匿名結(jié)構(gòu)字段的結(jié)構(gòu)一樣。理解這個(gè)定義是相當(dāng)復(fù)雜的。

type Address struct {  
    city, state string
}
type Person struct {  
    name string
    age  int
    Address
}

func main() {  
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.Address = Address{
        city:  "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("Age:", p.age)
    fmt.Println("City:", p.city) //city is promoted field
    fmt.Println("State:", p.state) //state is promoted field
}

運(yùn)行結(jié)果

Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

若存在匿名字段中的字段與非匿名字段名字相同,則最外層的優(yōu)先訪問,就近原則

嵌套結(jié)構(gòu)體的字段名沖突

嵌套結(jié)構(gòu)體內(nèi)部可能存在相同的字段名。在這種情況下為了避免歧義需要通過指定具體的內(nèi)嵌結(jié)構(gòu)體字段名。

//Address 地址結(jié)構(gòu)體
type Address struct {
    Province   string
    City       string
    CreateTime string
}

//Email 郵箱結(jié)構(gòu)體
type Email struct {
    Account    string
    CreateTime string
}

//User 用戶結(jié)構(gòu)體
type User struct {
    Name   string
    Gender string
    Address
    Email
}

func main() {
    var user User
    user.Name = "張三"
    user.Gender = "男"
    // user.CreateTime = "2021" //ambiguous selector user.CreateTime
    user.Address.CreateTime = "2000" //指定Address結(jié)構(gòu)體中的CreateTime
    user.Email.CreateTime = "2000"   //指定Email結(jié)構(gòu)體中的CreateTime
}

結(jié)構(gòu)體的“繼承”

Go語言中使用結(jié)構(gòu)體也可以實(shí)現(xiàn)其他編程語言中面向?qū)ο蟮睦^承。

//Animal 動(dòng)物
type Animal struct {
    name string
}

func (a *Animal) move() {
    fmt.Printf("%s會(huì)動(dòng)!\n", a.name)
}

//Dog 狗
type Dog struct {
    Feet    int8
    *Animal //通過嵌套匿名結(jié)構(gòu)體實(shí)現(xiàn)繼承
}

func (d *Dog) wang() {
    fmt.Printf("%s會(huì)汪汪汪~\n", d.name)
}

func main() {
    d1 := &Dog{
        Feet: 4,
        Animal: &Animal{ //注意嵌套的是結(jié)構(gòu)體指針
            name: "樂樂",
        },
    }
    d1.wang() //樂樂會(huì)汪汪汪~
    d1.move() //樂樂會(huì)動(dòng)!
}

結(jié)構(gòu)體字段的可見性

結(jié)構(gòu)體中字段大寫開頭表示可公開訪問(可以從其他包訪問它),小寫表示私有(僅在定義當(dāng)前結(jié)構(gòu)體的包中可訪問)。

結(jié)構(gòu)體與JSON序列化

JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式。易于人閱讀和編寫。同時(shí)也易于機(jī)器解析和生成。JSON鍵值對(duì)是用來保存JS對(duì)象的一種方式,鍵/值對(duì)組合中的鍵名寫在前面并用雙引號(hào)""包裹,使用冒號(hào):分隔,然后緊接著值;多個(gè)鍵值之間使用英文,分隔。

//Student 學(xué)生
type Student struct {
    ID     int
    Gender string
    Name   string
}

//Class 班級(jí)
type Class struct {
    Title    string
    Students []*Student
}

func main() {
    c := &Class{
        Title:    "101",
        Students: make([]*Student, 0, 200),
    }
    for i := 0; i < 10; i++ {
        stu := &Student{
            Name:   fmt.Sprintf("stu%02d", i),
            Gender: "男",
            ID:     i,
        }
        c.Students = append(c.Students, stu)
    }
    //JSON序列化:結(jié)構(gòu)體-->JSON格式的字符串
    data, err := json.Marshal(c)
    if err != nil {
        fmt.Println("json marshal failed")
        return
    }
    fmt.Printf("json:%s\n", data)
    //JSON反序列化:JSON格式的字符串-->結(jié)構(gòu)體
    str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`
    c1 := &Class{}
    err = json.Unmarshal([]byte(str), c1)
    if err != nil {
        fmt.Println("json unmarshal failed!")
        return
    }
    fmt.Printf("%#v\n", c1)
}

結(jié)構(gòu)體標(biāo)簽(Tag)

Tag是結(jié)構(gòu)體的元信息,可以在運(yùn)行的時(shí)候通過反射的機(jī)制讀取出來。 Tag在結(jié)構(gòu)體字段的后方定義,由一對(duì)反引號(hào)包裹起來,具體的格式如下:

`key1:"value1" key2:"value2"`

結(jié)構(gòu)體tag由一個(gè)或多個(gè)鍵值對(duì)組成。鍵與值使用冒號(hào)分隔,值用雙引號(hào)括起來。同一個(gè)結(jié)構(gòu)體字段可以設(shè)置多個(gè)鍵值對(duì)tag,不同的鍵值對(duì)之間使用空格分隔。

注意事項(xiàng): 為結(jié)構(gòu)體編寫Tag時(shí),必須嚴(yán)格遵守鍵值對(duì)的規(guī)則。結(jié)構(gòu)體標(biāo)簽的解析代碼的容錯(cuò)能力很差,一旦格式寫錯(cuò),編譯和運(yùn)行時(shí)都不會(huì)提示任何錯(cuò)誤,通過反射也無法正確取值。例如不要在key和value之間添加空格。

例如我們?yōu)?code>Student結(jié)構(gòu)體的每個(gè)字段定義json序列化時(shí)使用的Tag:

//Student 學(xué)生
type Student struct {
    ID     int    `json:"id"` //通過指定tag實(shí)現(xiàn)json序列化該字段時(shí)的key
    Gender string //json序列化是默認(rèn)使用字段名作為key
    name   string //私有不能被json包訪問
}

func main() {
    s1 := Student{
        ID:     1,
        Gender: "男",
        name:   "張三",
    }
    data, err := json.Marshal(s1)
    if err != nil {
        fmt.Println("json marshal failed!")
        return
    }
    fmt.Printf("json str:%s\n", data) //json str:{"id":1,"Gender":"男"}
}

結(jié)構(gòu)體比較

結(jié)構(gòu)體是值類型,如果每個(gè)字段具有可比性,則是可比較的。如果它們對(duì)應(yīng)的字段相等,則認(rèn)為兩個(gè)結(jié)構(gòu)體變量是相等的。

type name struct {  
    firstName string
    lastName string
}


func main() {  
    name1 := name{"Steve", "Jobs"}
    name2 := name{"Steve", "Jobs"}
    if name1 == name2 {
        fmt.Println("name1 and name2 are equal")
    } else {
        fmt.Println("name1 and name2 are not equal")
    }

    name3 := name{firstName:"Steve", lastName:"Jobs"}
    name4 := name{}
    name4.firstName = "Steve"
    if name3 == name4 {
        fmt.Println("name3 and name4 are equal")
    } else {
        fmt.Println("name3 and name4 are not equal")
    }
}

運(yùn)行結(jié)果

name1 and name2 are equal  
name3 and name4 are not equal  

如果結(jié)構(gòu)變量包含的字段是不可比較的,那么結(jié)構(gòu)變量是不可比較的

type image struct {  
    data map[int]int
}

func main() {  
    image1 := image{data: map[int]int{
        0: 155,
    }}
    image2 := image{data: map[int]int{
        0: 155,
    }}
    if image1 == image2 {
        fmt.Println("image1 and image2 are equal")
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 結(jié)構(gòu)體 什么是結(jié)構(gòu)體 Go 語言中數(shù)組可以存儲(chǔ)同一類型的數(shù)據(jù),但在結(jié)構(gòu)體中我們可以為不同項(xiàng)定義不同的數(shù)據(jù)類型。 結(jié)...
    yuyangray閱讀 448評(píng)論 0 1
  • 結(jié)構(gòu)體 結(jié)構(gòu)體(struct)是用戶自定義的類型,代表若干字段的集合。有時(shí)將多個(gè)數(shù)據(jù)看做一個(gè)整體要比單獨(dú)使用這些數(shù)...
    與蟒唯舞閱讀 977評(píng)論 0 2
  • 結(jié)構(gòu)體定義 go語言的關(guān)鍵字 type 可以將各種基本類型定義為自定義類型,包括整型、字符串、布爾等。結(jié)構(gòu)體是一種...
    Boston199834閱讀 627評(píng)論 0 2
  • 結(jié)構(gòu)體方法和接受者 在go中,沒有類的概念但是可以給類型(結(jié)構(gòu)體、自定義類型)定義方法。所謂方法就是定義了接受者的...
    learninginto閱讀 372評(píng)論 0 4
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,835評(píng)論 28 54

友情鏈接更多精彩內(nèi)容