日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

一文帶你了解Go語言中的指針和結(jié)構(gòu)體_Golang

作者:陳明勇 ? 更新時(shí)間: 2022-12-25 編程語言

前言

前面的兩篇文章對 Go 語言的基礎(chǔ)語法和基本數(shù)據(jù)類型以及幾個(gè)復(fù)合數(shù)據(jù)類型進(jìn)行介紹,本文將對 Go 里面的指針和結(jié)構(gòu)體進(jìn)行介紹,也為后續(xù)文章做鋪墊。

指針

Go 語言中,指針可以簡單理解是一個(gè)地址,指針類型是依托于某一個(gè)類型而存在的,例如 Go 里面的基本數(shù)據(jù)類型 intfloat64string 等,它們所對應(yīng)的指針類型為 *int*float64*string等。

指針的定義

語法格式:var 指針變量名 *數(shù)據(jù)類型 = &變量

& 為取地址符號,通過 & 符號獲取某個(gè)變量的地址,然后賦值給指針變量。

import (
	"fmt"
)

func main() {
	var num int = 666
	var numPtr *int = &num
	fmt.Println(numPtr)  // num 變量的地址值 0xc00001c098
	fmt.Println(&numPtr) // 指針變量本身的地址值 0xc00000a028
}

npmPtr 指針變量指向變量 num0xc00001c098num 變量的地址,0xc00000a028 為指針變量本身的地址值。

使用 new(T) 函數(shù)創(chuàng)建指針變量

import (
	"fmt"
)

func main() {
	numPtr := new(int)
	fmt.Println(numPtr)  // 0xc000122058
	fmt.Println(*numPtr) // 0
}

new(T) 函數(shù)為每個(gè)類型分配一片內(nèi)存,內(nèi)存單元保存的是對應(yīng)類型的零值,函數(shù)返回一個(gè)指針類型。

錯(cuò)誤的類型地址賦值

func main() {
	var num float64 = 666
	var numPtr *int = &num // cannot use &num (value of type *float64) as type *int in variable declaration
}

當(dāng)指針?biāo)劳械念愋团c變量的類型不一致時(shí),Go 編譯器會報(bào)錯(cuò),類型不匹配。

獲取和修改指針?biāo)赶蜃兞康闹?/h3>

通過指針獲取所指向變量的值

func main() {
	var num int = 666
	var numPtr *int = &num

	// 獲取 num 的值
	fmt.Println(*numPtr) // 666
}

對指針使用 * 操作符可以獲取所指向變量的值。

通過指針修改所指向變量的值

import (
	"fmt"
)

func main() {
	var num int = 666
	var numPtr *int = &num

	// 修改 num 的值
	*numPtr = 555
	fmt.Println(num) // 555
}

同時(shí)也可以對指針使用 * 操作符修改所指向變量的值。

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

通過上一篇文章,我們了解了數(shù)組和切片的特點(diǎn),它們可以存儲一組相同類型的數(shù)據(jù),而結(jié)構(gòu)體,它可以由 0 個(gè)或多個(gè)字段組成,每個(gè)字段的數(shù)據(jù)類型可以一樣,也可以不一樣。結(jié)構(gòu)體可以表示一個(gè)對象,例如:人,人包含的一些字段有姓名、性別和年齡等。

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

語法格式:

type XXX struct {
	/*
	結(jié)構(gòu)體字段定義區(qū)域
	*/
}

XXX 為結(jié)構(gòu)體的名字,下面以人為對象,引入結(jié)構(gòu)體

// Person定義一個(gè)人的結(jié)構(gòu)體
type Person struct {
	// 姓名
	Name string
	// 年齡
	Age int
	// 性別
	Sex string
	// 身份證號
	idNumber string
}

上述代碼定義了人的結(jié)構(gòu)體 Person,包含四個(gè)字段,字段的命名規(guī)則和變量是一樣的,前三個(gè)字段首字母大寫,可以被包外訪問,第四個(gè)字段首字母小寫,表示只能在包內(nèi)訪問。 除了上述的定義方式以外,結(jié)構(gòu)體里還可以內(nèi)嵌結(jié)構(gòu)體

// Person 定義一個(gè)人的結(jié)構(gòu)體
type Person struct {
	// 姓名
	Name string
	// 年齡
	Age int
	// 性別
	Sex string
	// 身份證號
	idNumber string
}

// Phone 手機(jī)結(jié)構(gòu)體
type Phone struct {
	// 品牌
	Brand string
	// 擁有者
	Owner Person
}

上述代碼定義了 Person 結(jié)構(gòu)體和 Phone 結(jié)構(gòu)體,Phone 結(jié)構(gòu)體擁有兩個(gè)字段,分別為 Brand 品牌和 Owner 擁有者,Owner 屬性的類型,指定為我們所自定義的 Person 結(jié)構(gòu)體。以這種方式定義的結(jié)構(gòu)體字段,我們可以稱為嵌入字段(Embedded Field)。也可以將這種字段稱為匿名字段。

結(jié)構(gòu)體的創(chuàng)建方式

1、聲明一個(gè)結(jié)構(gòu)體變量

// Person 定義一個(gè)人的結(jié)構(gòu)體
type Person struct {
	// 姓名
	Name string
	// 年齡
	Age int
	// 性別
	Sex string
	// 身份證號
	idNumber string
}

func main() {
	var person Person
	fmt.Println(person.Name)     // ""
	fmt.Println(person.Age)      // 0
	fmt.Println(person.Sex)      // ""
	fmt.Println(person.idNumber) // ""

	// 修改結(jié)構(gòu)體字段的值
	person.Name = "chenmingyong"
	fmt.Println(person.Name) // "chenmingyong"
}

通過聲明一個(gè)結(jié)構(gòu)體變量,隱式創(chuàng)建一個(gè)結(jié)構(gòu)體變量,這個(gè)結(jié)構(gòu)體變量各個(gè)字段值默認(rèn)為零值,也就是對應(yīng)類型的默認(rèn)值。

結(jié)構(gòu)體屬性的值,可以通過 變量.字段名 的方式獲取,同時(shí)也可以通過此方式對字段值進(jìn)行修改。

2、使用復(fù)合字面值進(jìn)行顯式初始化結(jié)構(gòu)體對象

import "fmt"

// Person 定義一個(gè)人的結(jié)構(gòu)體
type Person struct {
	// 姓名
	Name string
	// 年齡
	Age int
	// 性別
	Sex string
	// 身份證號
	idNumber string
}

func main() {
	person := Person{
		"chenmingyong",
		18,
		"男",
		"xxxxxxxxx",
	}

	fmt.Println(person) // {chenmingyong 18 男 xxxxxxxxx}
}

上述代碼根據(jù)字段的順序進(jìn)行賦值,實(shí)際上,Go 語言并不推薦我們用這種方式進(jìn)行賦值,因?yàn)榭赡軙硪恍﹩栴},例如結(jié)構(gòu)體的某個(gè)中間的字段被刪除或者字段的順序改變了,那么我們需要維護(hù)對應(yīng)代碼,調(diào)整賦值的順序。

上述創(chuàng)建結(jié)構(gòu)體的方式有弊端,因此我們需要換一種方法,如下第三種方法。

3、 使用 field:value 形式的復(fù)合字面值進(jìn)行顯式初始化結(jié)構(gòu)體對象

import "fmt"

// Person 定義一個(gè)人的結(jié)構(gòu)體
type Person struct {
	// 姓名
	Name string
	// 年齡
	Age int
	// 性別
	Sex string
	// 身份證號
	idNumber string
}

func main() {
	person := Person{
	    Sex:      "男",
	    Age:      18,
	    Name:     "chenmingyong",
	    idNumber: "xxxxxxxxx",
    }

	fmt.Println(person) // {chenmingyong 18 男 xxxxxxxxx}
}

通過以上的方式,我們就不被字段的順序所約束了。

4、通過 new(T) 函數(shù)創(chuàng)建結(jié)構(gòu)體指針

// Person 定義一個(gè)人的結(jié)構(gòu)體
type Person struct {
	// 姓名
	Name string
	// 年齡
	Age int
	// 性別
	Sex string
	// 身份證號
	idNumber string
}

func main() {
	person := new(Person)
	(*person).Name = "chenmignyong"
	fmt.Println((*person).Name) // chenmignyong
	// 簡化賦值,底層自動轉(zhuǎn)換成 (*person).Age = 18
	person.Age = 18
	fmt.Println(person.Age) // 18
}

前面提到過,訪問指針?biāo)赶蜃兞康闹担枰褂?* 操作符,但在結(jié)構(gòu)體這里有點(diǎn)特殊,如果不加 * 的話,底層會將 person.Age = 18 轉(zhuǎn)成 (*person).Age = 18

小結(jié)

本文對指針和結(jié)構(gòu)體進(jìn)行了介紹,也指出使用指針和結(jié)構(gòu)體時(shí)需要注意的一些地方。因?yàn)楸疚氖腔诹私獾膶用嫒懙奈恼拢恍┥钊氲闹R并沒有提到,然后也沒有提到結(jié)構(gòu)體的方法,是因?yàn)榇蛩懔舻胶竺婧秃瘮?shù)一起去介紹。

原文鏈接:https://juejin.cn/post/7169961029328175112

欄目分類
最近更新