十一、結構體嵌入

1.命名嵌入

結構體命名嵌入是指結構體中的屬性對應的類型也是結構體

package main

import "fmt"

type Addrs struct {
   Region string
   Street string
}

type Users struct {
   ID   int
   Name string
   Addr Addrs
}

func main() {
   //結構體命名嵌入
   var user Users = Users{
      ID:   2,
      Name: "aa",
      Addr: Addrs{
         Region: "bbb",
         Street: "ccc",
      },
   }
   fmt.Println(user)
   fmt.Println(user.Addr.Region)
   user.Addr.Region = "543"
   fmt.Println(user.Addr.Region)

}

2.匿名嵌入

結構體匿名嵌入是指將已定義的結構體名直接聲明在新的結構體中,從而實現對以後已有類
型的擴展和修改
在訪問和修改嵌入結構體的屬性值時,可以通過對象名.結構體名稱.屬性名的方式進行訪問
和修改,結構體名稱可以省略(匿名成員有一個隱式的名稱),因此不能嵌套兩個相同名稱
的結構體。當被嵌入結構體和嵌入結構體有相同的屬性名時,在訪問和修改嵌入結構體成員
的屬性值時不能省略結構體名稱

package main

import "fmt"

//匿名嵌入結構體就是兩種情況
//1.嵌入結構體與外層有相同屬性,省略匿名訪問,訪問的是外層屬性
//2.兩個嵌入結構體都有同屬性,訪問不能省略匿名,必須全路徑訪問
type Addrs struct {
   Region string
   Street string
}

type Users struct {
   ID   int
   Name string
   Addr Addrs
}

type Company struct {
   Name string
}

//如果匿名嵌入結構體 嵌入2個或者多個結構體並且都具有相同的屬性,那麼訪問必須全路徑訪問不然會報錯找不到
//因爲查找對應屬性省略匿名的話他是遞進去查找如果最外層有那麼就直接返回,沒有會繼續到下一層去找
type Employee struct {
   Users
   Salary float64
   Company
}

func main() {
   m1 := Employee{}
   m1.Users.Name = "aa"
   m1.Company.Name = "bb"
   fmt.Printf("%#v", m1)
}

3.指針類型嵌入

結構體嵌入(命名&匿名)類型也可以爲結構體指針
(1)命名

package main

import "fmt"

//指針命名嵌入
type Addrs struct {
   Region string
   Street string
}

type Users struct {
   ID   int
   Name string
   Addr *Addrs
}

func main() {
   //未初始化值 返回對應屬性的零值 指針的零值是nil
   m := Users{}
   fmt.Printf("%#v\n", m)
   m = Users{
      ID:   1,
      Name: "aa",
      Addr: &Addrs{
         Region: "西安",
         Street: "錦未央",
      },
   }
   fmt.Printf("%#v\n", m)
   fmt.Println(m.Addr.Region)
   m.Addr.Region = "北京"
   fmt.Println(m.Addr.Region)
}

(2)匿名

package main

import "fmt"

//指針匿名嵌入
type Addrs struct {
   Region string
   Street string
   Name   string
}

type Users struct {
   ID   int
   Name string
   *Addrs
}

func main() {
   //未初始化值 返回對應屬性的零值 指針的零值是nil
   m := Users{}
   fmt.Printf("%#v\n", m)
   m = Users{
      ID:   1,
      Name: "aa",
      Addrs: &Addrs{
         Region: "西安",
         Street: "錦未央",
         Name:   "bb",
      },
   }
   fmt.Printf("%#v\n", m)
   fmt.Println(m.Addrs.Region)
   fmt.Println(m.Name)
}

4.值類型與指針類型嵌入的區別

(1)值類型
值類型賦值給變量1 變量1賦值給變量2 修改變量2 變量1並不會被修改

package main

import "fmt"

//結構體是值類型 在賦值的時候相當於copy了一份 修改賦值之後 並不會影響其本身,如果結構體中有指針引用另說
type Addrs struct {
   Region string
   Street string
}

type Users struct {
   ID   int
   Name string
   Addr Addrs
   bb   []int
}

//這裏修改對之前並沒有影響
func change(m Users) {
   m.Name = "yyy"
}

//因爲這裏傳遞的是指針 是一個內存地址 那麼修改之後內存地址對應的就會被改
func Change(m *Users) {
   m.Name = "nnn"
}

func main() {
   m1 := Users{}
   m2 := m1
   m2.Name = "aa"
   m2.Addr.Street = "bbb"
   m2.bb = []int{1, 2, 3, 4}
   fmt.Printf("%#v\n", m1)
   fmt.Printf("%#v\n", m2)

   change(m2)
   fmt.Printf("%#v\n", m2)
   Change(&m2)
   fmt.Printf("%#v\n", m2)
}

(2)指針類型
值類型賦值給變量1 變量1賦值給變量2 修改變量2 變量1會被修改

package main

import "fmt"

type Addrs struct {
   Region string
   Street string
}

type Users struct {
   ID   int
   Name string
   Addr *Addrs
}

func main() {
   m1 := Users{
      ID:   11,
      Name: "aaa",
      Addr: &Addrs{
         Region: "北京",
         Street: "宋家莊",
      },
   }
   m2 := m1
   m2.Name = "bb"
   fmt.Printf("%#v\n", m1.Addr)
   fmt.Printf("%#v\n", m2.Addr)
   m2.Addr.Street = "bbb"
   fmt.Printf("%#v\n", m1.Addr)
   fmt.Printf("%#v\n", m2.Addr)

}

結構體中如果有切片映射這種引用類型 賦值多個變量也會被影響

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章