天天看點

5.Go語言的結構體struct

作者:大胡幾哥哥

前面學習了 數組Array、切片Slice、字典Map類型,這三種類型都隻能存儲相同類型的值。結構體struct可以存儲不同類型的資料,結構體式不同類型的資料構成的資料集合。

Go語言中沒有Class類,是以結構體struct相當于其他語言中的Class。

聲明結構體

注意:結構體名首字母大寫其他包可以通路,首字母不是大寫的隻在本包内能通路到。

type 結構體名 struct {
    成員名   成員類型
    成員名   成員類型
    ...
    成員名   成員類型
}           

一旦定義了結構體它就可以被`執行個體化`,但寫法有講究。例如:

// 定義一個 student 的結構體
type student struct {
    name string
    age int
}

// 執行個體化結構體
// 正确1
// 如果不指定成員名稱,需要按照定義的順序依次寫出成員的值
var stu0 = student{"張三", 20}
fmt.Println("正确1", stu0)

// 錯誤
// 如果不指定成員名稱,沒有完全指定成員的值會報錯
// var stu1 = student{"錯誤"}
// fmt.Println(stu1)

// 正确2
// 指定成員名稱,給全部成員指派
stu2 := student{name: "李四", age: 18}
fmt.Println("正确2", stu2)

// 正确3
// 指定成員名稱,可以隻給部分成員指派,未指派成員将被賦對應類型的預設值
stu3 := student{name: "王五"}
fmt.Println("正确3", stu3)

// 正确4
// 隻定義一個student類型的變量,不指派成員,所有成員使用對應類型的預設值
var stu4 student
fmt.Println("正确4", stu4)

// 正确5
// 定義一個student類型的變量,指派部分成員,其他未指派成員使用對應類型的預設值
var stu5 student
stu5.age = 20
fmt.Println("正确5", stu5)

// 多行的錯誤寫法
// 當多行形式時,最後一行 `age:21` 和 `}` 不在一行會報錯
// var stu6 student = student{
//		  name: "老六",
//      age: 21
// }

// 多行的正确寫法有兩種
// 第一種在`age:21`後加`,`
var stu6 student = student{
		  name: "老六",
      age: 21,
}
fmt.Println("多行正确1", stu6)

// 第二種把`age:21` 和`}` 寫在一行
var stu7 student = student{
		  name: "老六",
      age: 21 } // 隻要一行,中間有空格也行
fmt.Println("多行正确2", stu7)           
5.Go語言的結構體struct

通路結構體成員

實用 . 來通路:

結構體.成員名

// 例如
var stu5 student
stu5.age = 20           

結構體作為函數參數

package main

import "fmt"

type student struct {
	name string
	age  int
}

func main() {

	var stu0 = student{"張三", 20}

  // 傳遞student類型的參數
	print(stu0)
}

// 參數類型是student的結構體
func print(s student) {
	fmt.Println(s)
}           
5.Go語言的結構體struct

結構體指針

如果我們有一個指向結構體的指針 p,那麼可以通過 (*p).X 來通路其字段 X。不過這麼寫太啰嗦了,是以語言也允許我們使用隐式間接引用,直接寫 p.X 就可以。使用new()進行執行個體化操作時,會生成一個結構體指針變量。

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
		v := Vertex{1, 2}
		p := &v
  
		p.X = 10
		fmt.Println(v)
  
		(*p).X = 20
		fmt.Println(v)
  
    // 使用new()進行執行個體化操作時,會生成一個結構體指針變量。
    v1 := new(Vertex)
    (*v1).X = 66
    fmt.Println(v1)
  
     v1.X = 88
     fmt.Println(v1)
}           
5.Go語言的結構體struct

結構體的方法

别人寫的文章中說 在 Go 語言中,我們無法在結構體内定義方法,必須使用組合函數的方式來定義結構體方法。組合函數的寫法如下:

package main

import "fmt"

// 定義 student 結構體
type student struct {
	name string
	age  int
}

// 為結構體綁定方法:在函數名前面加括号,括号裡面定義一個結構體類型的變量
func (stu student) getName() string {
	return stu.name
}

func main() {
	// 執行個體化結構體 stu1
	var stu1 student = student{
		name: "張三",
		age:  30,
	}

	// 因為 getName 方法已經綁定到 student 結構體中
	// 是以 執行個體 stu1 可以直接調用 getName
	name := stu1.getName()

	fmt.Println(name)
}           
5.Go語言的結構體struct

為結構體綁定方法:在函數名前面加括号,括号裡面定義一個結構體類型的變量。

需要注意的是上面這種綁定方式,在方法内改變成員的值,沒有改變實際對象的值,就是我們平時說的值傳遞。如果要改變需要指針傳遞。

package main

import "fmt"

// 定義 student 結構體
type student struct {
	name string
	age  int
}

// 為結構體綁定方法,值形式綁定
func (stu student) getName() {
	stu.name = "zhangsan"
}

// 指針形式綁定
func (stu *student) changeName() {
	stu.name = "王五"
}

func main() {
	// 執行個體化結構體 stu1
	var stu1 student = student{
		name: "張三",
		age:  30,
	}
	fmt.Println("初始值", stu1.name)

	// 因為 getName 方法已經綁定到 student 結構體中
	// 是以 執行個體 stu1 可以直接調用 getName
	stu1.getName()
	fmt.Println("值綁定", stu1.name)

	// 這個方法是指針綁定
	stu1.changeName()
	fmt.Println("指針綁定", stu1.name)
}
           
5.Go語言的結構體struct

結構體嵌套

結構體可以互相嵌套實作複雜,使用的“繼承”功能。

package main

import "fmt"

// 定義 student 結構體
type student struct {
	name string
	age  int
}

type class struct {
	className  string
	classLevel int
	student    // 匿名字段
}

func main() {
	// 執行個體化結構體 stu1
	var stu1 student = student{
		name: "張三",
		age:  30,
	}

	var class1 class = class{
		className:  "1年級",
		classLevel: 1,
		student:    stu1,
	}

	fmt.Println(class1, class1.student.name)
}
           
5.Go語言的結構體struct