GO基礎之結構體


1 、什麼是結構體
GO語言中數組能夠存儲同一類型的數據,但在結構體中咱們能夠爲不一樣項定義不一樣的數據類型。結構體是由一系列具備相同類型或不一樣類型的數據構成的數據集合。

二、什麼是實例化?程序員

  • Go結構體的定義只是一種內存佈局的描述,只有當結構體實例化時,纔會真正分配內存。所以必須在定義結構體並實例化後才能使用結構體實例化就是根據結構體定義的格式建立一份與格式一致的內存區域。
  • 結構體實例之間的內存是徹底獨立的。
package main

import "fmt"

func main() {
    //實例化方式一
    var stu1 Student
    fmt.Printf("stu1=%T,%v,%q \n", stu1, stu1, stu1)
    stu1.name = "zs"
    stu1.age = 12
    stu1.sex = 1
    fmt.Printf("stu1=%T,%v,%q \n", stu1, stu1, stu1)
    //實例化方式二
    stu2 := Student{}
    stu2.name = "David"
    stu2.age = 33
    stu2.sex = 1
    fmt.Printf("stu2=%T,%v,%q \n", stu2, stu2, stu2)
    //實例化方式三
    stu3 := Student{
        name: "Josh",
        age:  28,
        sex:  1,
    }
    fmt.Printf("stu3=%T,%v,%q \n", stu3, stu3, stu3)
    //實例化四
    stu4 := Student{"Ruby", 30, 0}
    fmt.Printf("stu3=%T,%v,%q \n", stu4, stu4, stu4)
    //實例化五
    //使用內置函數new()對結構體進行實例化,結構體實例化後造成指針類型的結構體
    //·new內置函數會分配內存。第一個參數是類型,而不是值,返回的值是指向該類型新分配的零值的指針。該函數用於建立某個類型的指針。
    stu5 := new(Student)
    (*stu5).name = "Running"
    (*stu5).age = 31
    stu5.sex = 0                                     //語法糖的方式
    fmt.Printf("stu3=%T,%v,%q \n", stu5, stu5, stu5) //stu3=*main.Student,&{Running 31 0},&{"Running" '\x1f' '\x00'}

}

//結構體的定義
type Student struct {
    name string
    age  int
    sex  int8
}
View Code

語法糖的概念( Syntactic sugar)編程

  • 語法糖,也譯爲糖衣語法,是由英國計算機科學家彼得·約翰·蘭達( PeterJ.Landin)發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並無影響,可是更方便程序員使用。
  • 一般來講使用語法糖可以增長程序的可讀性,從而減小程序代碼岀錯的機會
  • 結構體和數組中都含有語法糖。
package main

import "fmt"

func main() {
    arr := [4]int{1, 2, 3, 4}
    arr2 := &arr
    fmt.Println((*arr2)[3])
    //數組中的語法糖
    fmt.Println(arr2[3])
    
    //切片
    arr3 := []int{10, 20, 30, 40}
    arr4 := &arr3
    fmt.Println((*arr4)[3])
    //切片中沒有語法糖
    //fmt.Println(arr4[3])
}
View Code

 

三、結構體是值類型傳遞數組

2、深拷貝與淺拷貝

struct 默認是深拷貝ide

package main

import "fmt"

func main() {
    stu1 := Student{"zs", 18, 0}
    fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
    //stu1:=main.Student,0xc0000044a0,{zs 18 0}
    stu2 := stu1
    stu2.name = "ls"
    fmt.Printf("stu2:=%T,%p,%v \n", stu2, &stu2, stu2)
    //stu2:=main.Student,0xc000004520,{ls 18 0}
    
    fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
    //stu1:=main.Student,0xc0000044a0,{zs 18 0}
    //修改stu2對stu1沒有任何影響

}
View Code

 

實現淺拷貝函數

一、直接賦值指針地址佈局

package main

import "fmt"

func main() {
    stu1 := Student{"zs", 18, 0}
    fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
    //stu1:=main.Student,0xc00005a440,{zs 18 0}
    stu2 := &stu1
    stu2.name = "ls"
    fmt.Printf("stu2:=%T,%p,%v \n", stu2, stu2, stu2)
    //stu2:=*main.Student,0xc00005a440,&{ls 18 0}

    fmt.Printf("stu1:=%T,%p,%v \n", stu1, &stu1, stu1)
    //stu1:=main.Student,0xc00005a440,{ls 18 0}
    //修改stu2對stu1有影響
}
View Code

 二、實現結構體淺拷貝:經過new()函數來實例化對象this

package main

import "fmt"

func main() {
    //三、實現結構體淺拷貝:經過new()函數來實例化對象
    d4 := new(Dog)
    d4.name = "多多"
    d4.color = "棕色"
    d4.age = 1
    d4.kind = "巴哥犬"
    d5 := d4
    fmt.Printf("d4: %T , %v , %p \n", d4, d4, d4)
    //d4: *main.Dog , &{多多 棕色 1 巴哥犬} , 0xc000040080
    fmt.Printf("d5: %T , %v , %p \n", d5, d5, d5)

    fmt.Println("--------------------------------------")

    d5.color = "金色"
    d5.kind = "金毛"
    fmt.Println("d5修改後:", d5)
    //d5修改後: &{多多 金色 1 金毛}
    fmt.Println("d4:", d4)
    //d4: &{多多 金色 1 金毛}
}

type Dog struct {
    name  string
    color string
    age   int8
    kind  string
}
View Code

 3、struct作函數參數

結構體對象或指針做爲函數的參數及函數返回值spa

  • 結構體對象做爲函數參數與結構體指針做爲函數參數的不一樣
  • 結構體對象做爲函數返回值與結構體指針做爲函數返回值的不一樣

 

 

4、匿名結構體和匿名字段

匿名結構體3d

  • •沒有名字的結構體。無需經過type關鍵字定義就能夠直接使用。
  • •在建立匿名結構體時,同時要建立對象。
  • •匿名結構體由結構體定義和鍵值對初始化兩部分組成
    //匿名結構體
    addr := struct {
        province, city string
    }{"陝西省", "西安市"}
    fmt.Println(addr)

結構體的匿名字段
結構體中的字段沒有名字,只包含一個沒有字段名的類型。這些字段被稱爲匿名字段。指針

  • •若是字段沒有名字,那麼默認使用類型做爲字段名。
  • •注意:同一個類型只能寫一個。
  • •結構體嵌套中採用匿名結構體字段能夠模擬繼承關係。
package main

import "fmt"

type User struct {
    string
    byte
    int8
    float64
}

func main() {
    //    實例化結構體
    user:= User{"Steven" , 'm' , 35 , 177.5}
    fmt.Println(user)
    //若是想依次輸出姓名、年齡、身高、性別
    fmt.Printf("姓名:%s \n" , user.string)
    fmt.Printf("身高:%.2f \n" , user.float64)
    fmt.Printf("性別:%c \n" , user.byte)
    fmt.Printf("年齡:%d \n" , user.int8)
}
View Code

5、結構體的聚合

•將一個結構體做爲另外一個結構體的屬性(字段),這種結構就是結構體嵌套。
•結構體嵌套能夠模擬面向對象中的兩種關係:

  • 〇聚合關係:一個類做爲另_個類的屬性
  • 〇繼承關係:一個類做爲另外一個類的子類。子類和父類。
package main

import "fmt"

type Address struct {
    province, city string
}

type Person struct {
    name    string
    age     int
    address *Address
}

func main() {
    //模擬結構體對象之間的聚合關係
    p := Person{}
    p.name = "Steven"
    p.age = 35

    //賦值方式1:
    addr := Address{}
    addr.province = "北京市"
    addr.city = "海淀區"
    p.address = &addr

    fmt.Println(p)
    fmt.Println("姓名:", p.name)
    fmt.Println("年齡:", p.age)
    fmt.Println("省:", p.address.province)
    fmt.Println("市:", p.address.city)
    fmt.Println("-----------------------")

    //修改Person對象的數據,是否會影響Address對象的數據?
    p.address.city = "昌平區"
    fmt.Println("姓名:", p.name)
    fmt.Println("年齡:", p.age)
    fmt.Println("省:", p.address.province)
    fmt.Println("市:", p.address.city)
    fmt.Println("addr市:", addr.city) //?是否會受到影響?
    fmt.Println("-----------------------")

    //修改Address對象的數據,是否會影響Person對象的數據?
    addr.city = "大興區"
    fmt.Println("姓名:", p.name)
    fmt.Println("年齡:", p.age)
    fmt.Println("省:", p.address.province)
    fmt.Println("市:", p.address.city)
    fmt.Println("addr市:", addr.city) //?是否會受到影響?
    fmt.Println("-----------------------")

    //賦值方式2
    p.address = &Address{
        province: "陝西省",
        city:     "西安市",
    }
    fmt.Println(p)
    fmt.Println("姓名:", p.name)
    fmt.Println("年齡:", p.age)
    fmt.Println("省:", p.address.province)
    fmt.Println("市:", p.address.city)
    fmt.Println("-----------------------")
}
View Code

6、結構體嵌套模擬繼承關係

•繼承是傳統面向對象編程中三大特徵之一。用於描述兩個類之間的關係。一個類(子類、派生類)繼承於另外一個類(父類、超類)。
•子類能夠有本身的屬性和方法,也能夠重寫父類已有的方法。
•子類能夠直接訪問父類全部的屬性和方法。
•提高字段:
  〇在結構體中屬於匿名結構體的字段稱爲提高字段,由於它們能夠被訪問,就好像它們屬於擁有匿名結構字段的結構同樣。
  〇換句話說,父類中的字段就是提高字段。
•繼承的意義:避免重複代碼、擴展類的功能
•採用匿名字段的形式就是模擬繼承關係。而模擬聚合關係時必定要採用有名字的結構體做爲字段

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
    sex  string
}

type Student struct {
    Person
    schoolName string
}

func main() {
    //一、實例化並初始化Person
    p1 := Person{"Steven", 35, ""}
    fmt.Println(p1)
    fmt.Println("-------------------")

    //二、實例化並初始化Student
    //    寫法1:
    s1 := Student{p1, "北航軟件學院"}
    printInfo(s1)

    //寫法2:
    s2 := Student{Person{"Josh", 30, ""}, "北外高翻學院"}
    printInfo(s2)

    //寫法3:
    s3 := Student{Person: Person{
        name: "Penn",
        age:  19,
        sex:  "",
    },
        schoolName: "北大元培學院",
    }
    printInfo(s3)

    //    寫法4:
    s4 := Student{}
    s4.name = "Daniel"
    s4.sex = ""
    s4.age = 12
    s4.schoolName = "北京十一龍樾"
    printInfo(s4)

}

func printInfo(s1 Student) {
    fmt.Println(s1)
    fmt.Printf("%+v \n", s1)
    fmt.Printf("姓名:%s, 年齡:%d , 性別:%s ,學校:%s \n", s1.name, s1.age, s1.sex, s1.schoolName)
    fmt.Println("-------------------")
}
View Code

 

7、結構體中的方法

 

• Go語言同時有函數和方法,方法的本質是函數,可是方法和函數又具備不一樣點。
一、 含義不一樣
•函數function是一段具備獨立功能的代碼,能夠被反覆屢次調用,從而實現代碼複用。而方法method是一個類的行爲功能,只有該類的對象才能調用。
二、 方法有接受者,而函數無接受者
• Go語言的方法methods—種做用於特定類型變量的函數。這種特定類型變量叫作Receiver (接受者、接收者、接收器)。
•接受者的概念相似於傳統面嚮對象語言中的this或self關鍵字。
• Go語言的接受者強調了方法具備做用對象,而函數沒有做用對象。
•—個方法就是一個包含了接受者的函數。
• Go語言中,接受者的類型能夠是任何類型,不只僅是結構體,也能夠是struct類型外的其餘任何類型。
三、 函數不能夠重名,而方法能夠重名
•只要接受者不一樣,則方法名能夠同樣。

package main

import "fmt"
import "base"
type Employee struct {
    name , currency string
    salary float64
}
func main() {
    emp1 := Employee{"Daniel" , "$" , 2000}
    emp1.printSalary()//員工姓名:Daniel ,薪資:$2000.00 
    emp1.updateSalary(1000)
    emp1.printSalary()//員工姓名:Daniel ,薪資:$1000.00 
}

//printSalary方法
func (e Employee) printSalary() {
    fmt.Printf("員工姓名:%s ,薪資:%s%.2f \n", e.name , e.currency , e.salary)
}
func (e *Employee) updateSalary(num float64)  {
    e.salary=num
}
View Code

方法的繼承與重寫

package main

import "fmt"
import "base"

type Human struct {
    name, phone string
    age         int
}

type Student struct {
    Human
    school string
}

type Employee struct {
    Human
    company string
}

func main() {
    s1 := Student{Human{"Daniel", "15012345678", 13}, "十一龍樾"}
    e1 := Employee{Human{"Steven", "17812345678", 35}, "1000phone"}
    s1.printName()
    e1.printName()
    s1.SayHi()
    e1.SayHi()
}
//======================方法的繼承=============================
func (h *Human) printName() {
    fmt.Println("你們好!我是%s ", h.name)
}

//=====================方法的重寫=============================
func (h *Human) SayHi() {
    fmt.Printf("你們好!我是%s , 我%d歲 , 聯繫方式:%s \n", h.name, h.age, h.phone)
}

func (s *Student) SayHi() {
    fmt.Printf("你們好!我是%s , 我%d歲 , 我在%s上學,聯繫方式:%s \n", s.name, s.age, s.school, s.phone)
}

func (e *Employee) SayHi() {
    fmt.Printf("你們好!我是%s , 我%d歲 , 我在%s工做,聯繫方式:%s \n", e.name, e.age, e.company, e.phone)
}
View Code
相關文章
相關標籤/搜索