欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一起聊聊Go語(yǔ)言中的語(yǔ)法糖的使用

 更新時(shí)間:2022年07月25日 09:18:06   作者:山姆劉  
語(yǔ)法糖通常是用來(lái)簡(jiǎn)化代碼編寫(xiě)的,特性就是使用語(yǔ)法糖前后編譯的結(jié)果是相同的。這篇文章主要就來(lái)和大家一起聊聊Go語(yǔ)言中的語(yǔ)法糖的實(shí)現(xiàn)

前言

由于工作變動(dòng),我現(xiàn)在已經(jīng)開(kāi)始使用Golang了。用了一段時(shí)間之后,我發(fā)現(xiàn)Golang(后面簡(jiǎn)稱(chēng)Go)中的語(yǔ)法糖還蠻多的,有些語(yǔ)法糖還讓會(huì)讓人很懵逼。那么接下來(lái),讓我以一個(gè)曾經(jīng)的 Java CURD boy,來(lái)說(shuō)一說(shuō) Go 中的語(yǔ)法糖。

進(jìn)入正題

至于什么是語(yǔ)法糖,名詞解釋我就不解釋了,老司機(jī)自然是懂,新手司機(jī)想了解的可以去百度問(wèn)一下。閑話(huà)少說(shuō)我們直接開(kāi)講。

可變長(zhǎng)參數(shù)

Go語(yǔ)言允許一個(gè)函數(shù)把任意數(shù)量的值作為參數(shù),Go語(yǔ)言?xún)?nèi)置了... 操作符,在函數(shù)的最后一個(gè)形參才能使用...操作符,使用它必須注意如下事項(xiàng)

  • 可變長(zhǎng)參數(shù)必須在函數(shù)列表的最后一個(gè);
  • 把可變長(zhǎng)參數(shù)當(dāng) 切片來(lái)解析,可變長(zhǎng)參數(shù)沒(méi)有沒(méi)有值時(shí)就是個(gè)空切片
  • 可變長(zhǎng)參數(shù)的類(lèi)型必須相同
func test(a int, b ...int) {
	fmt.Println("a=", a, ",b=", b, ",b的類(lèi)型=", reflect.TypeOf(b))
	return
}

輸出結(jié)果如下:

a= 1 ,b= [] ,b的類(lèi)型= []int

為啥說(shuō)可變長(zhǎng)參數(shù)的值用切片來(lái)解析,而不是數(shù)組。為什么是這樣有興趣的朋友可以思考一下

可變長(zhǎng)參數(shù)這個(gè)語(yǔ)法糖,不是Go獨(dú)有的,Java中也有,不同的是Java是通過(guò)數(shù)組實(shí)現(xiàn)此語(yǔ)法糖的。從實(shí)際開(kāi)發(fā)經(jīng)驗(yàn)來(lái)看,這個(gè)語(yǔ)法糖我在使用Java開(kāi)發(fā)時(shí),貌似一次都沒(méi)有用過(guò),用Go開(kāi)發(fā)的時(shí)候我用的次數(shù)還挺多的,具體在什么地方用,后面有機(jī)會(huì)我再說(shuō)說(shuō)它是如何使用的。

聲明不定長(zhǎng)數(shù)組

我么都知道數(shù)組長(zhǎng)度是固定的,所以在聲明數(shù)組的時(shí)候都要指定長(zhǎng)度,Go里提供了一種偷懶的聲明方式,即使用...操作符聲明數(shù)組時(shí),我們只管填充元素值,其他的由Go編譯器來(lái)處理。

// Go的實(shí)現(xiàn):數(shù)組長(zhǎng)度是4,等同于 a := [4]{1, 2, 3, 4}
a := [...]int{1, 2, 3, 4}

這個(gè)Java中有實(shí)現(xiàn),而且感覺(jué)比Go的還簡(jiǎn)單,具體如下:

// Java的實(shí)現(xiàn):數(shù)組長(zhǎng)度是4
int[] x = {1,2,3,4};

在我短暫的職業(yè)生涯中,無(wú)論我使用Java還是Go開(kāi)發(fā)的時(shí)候,數(shù)組使用的頻率都是比較少的。

ps 我發(fā)現(xiàn)這個(gè)...好像也算是一個(gè)語(yǔ)法糖

... 操作符

...這個(gè)叫啥名字,我也沒(méi)有找到官方的叫法。但是我發(fā)現(xiàn)在Go實(shí)際的開(kāi)發(fā)過(guò)程中用的地方還蠻多的。

  • 函數(shù)的參數(shù)聲明。 如:func funcName(nums ...int),在函數(shù)的方法體內(nèi),nums作為一個(gè)切片[]int來(lái)使用,這個(gè)上面已經(jīng)提到了。
  • 傳參時(shí)列表打散。 如:params = []int{1,2,3},調(diào)用某個(gè)有三個(gè)參數(shù)的方法 func ThreeParamFunc(a, b, c int)時(shí)可以ThreeParamFunc(params...)。三個(gè)點(diǎn)...在JavaScript中的名叫擴(kuò)展運(yùn)算符,是在ES6中新增加的內(nèi)容,它可以在函數(shù)調(diào)用/數(shù)組構(gòu)造時(shí),將數(shù)組表達(dá)式或者string在語(yǔ)法層面展開(kāi);還可以在構(gòu)造字面量對(duì)象時(shí)將對(duì)象表達(dá)式按照key-value的方式展開(kāi),例如:
// 數(shù)組
var number = [1,2,3,4,5,6]
console.log(...number) //1 2 3 4 5 6
//對(duì)象
var man = {name:'蔡',height:180}
console.log({...man}) / {name:'蔡',height:180}

所以我覺(jué)得在Go里面在這種情況下,我們也可以稱(chēng)...為擴(kuò)展運(yùn)算符。

  • 聲明不定長(zhǎng)數(shù)組。 如果元素指定,那么可以不必顯式聲明數(shù)組長(zhǎng)度,可以根據(jù)元素個(gè)數(shù)推斷,如:arr := [...]int{1,2,3} ,這個(gè)上面已經(jīng)提到了。
  • 在 go 命令行中,被當(dāng)做包列表的通配符。如:$ go test ./... 這條命令會(huì)執(zhí)行當(dāng)前目錄及子目錄下的所有包測(cè)試文件。

切片循環(huán)

在Go中提供了for range語(yǔ)法來(lái)快速迭代對(duì)象。數(shù)組、切片、字符串、map、channel等等類(lèi)型都可以使用這種方式進(jìn)行遍歷,總結(jié)起來(lái)有以下幾種形式:

只遍歷不關(guān)心數(shù)據(jù),適用于切片、數(shù)組、字符串、map、channel

for range T {}

遍歷獲取索引或數(shù)組,切片,數(shù)組、字符串就是索引,map就是key,channel就是數(shù)據(jù)

for key := range T{}

遍歷獲取索引和數(shù)據(jù),適用于切片、數(shù)組、字符串,第一個(gè)參數(shù)就是索引,第二個(gè)參數(shù)就是對(duì)應(yīng)的元素值,map 第一個(gè)參數(shù)就是key,第二個(gè)參數(shù)就是對(duì)應(yīng)的值;

for key, value := range T{}

其實(shí)在實(shí)際開(kāi)發(fā)中,我們會(huì)大概率會(huì)遇到遍歷map時(shí),只關(guān)心map中的數(shù)據(jù),不關(guān)心key的情況。這個(gè)時(shí)候我們就是使用最后一種方式,這個(gè)key聲明了但是沒(méi)有用,Go這個(gè)時(shí)候就會(huì)提示一個(gè)語(yǔ)法錯(cuò)誤key沒(méi)有使用,那我們只好使用Go的另外一個(gè)語(yǔ)法糖_忽略標(biāo)識(shí)符(就是一個(gè)下劃線(xiàn))忽略key,具體如下:

for _, value := range T{}

在Java中循環(huán)map的方式有很多種,但有一點(diǎn)就是,開(kāi)發(fā)者可以使用keySet()values()選擇遍歷key或者value。

// 打印鍵集合
for (String key : map.keySet()) {
    System.out.println(key);
}
// 打印值集合
for (String value : map.values()) {
    System.out.println(value);
}

另外注意一點(diǎn),在Go中如果一個(gè)切片是nil的時(shí)候,我們對(duì)他進(jìn)行遍歷或者append操作的時(shí)候,是不會(huì)出現(xiàn)報(bào)錯(cuò)的,這一點(diǎn)很不錯(cuò),省的像用Java時(shí)遍歷對(duì)象需要判斷他是否為null。

func main() {

	temp := make([]int, 0)
	temp = nil

	for _, val := range temp {
		fmt.Println("val=", val)
	}
	temp = append(temp, 1)
	fmt.Println("val=", temp)
}

上述操作都是不會(huì)報(bào)錯(cuò)的,大家放心食用!

忽略變量、字段或者導(dǎo)包

這個(gè)前面提到了一點(diǎn),使用_忽略變量。在Go中還有其他幾種常見(jiàn)的場(chǎng)景,具體如下:

json序列化忽略某個(gè)字段 我們都會(huì)對(duì)struct做序列化操作,但有些時(shí)候我們想要json里面的某些字段不參加序列化,Go語(yǔ)言的結(jié)構(gòu)體提供標(biāo)簽功能,在結(jié)構(gòu)體標(biāo)簽中使用 - 操作符就可以對(duì)不需要序列化的字段做特殊處理,使用如下:

type Item struct{
  Id uint32 `json:"id"`
  Name string `json: "name"`
  Password string `json: "-"`
}

這個(gè)Java中也有類(lèi)似的實(shí)現(xiàn),只要在Java類(lèi)的屬性前加上transient關(guān)鍵字修飾即可。當(dāng)然在將Java類(lèi)序列化成json時(shí)可以使用對(duì)應(yīng)的注解,這里我就不細(xì)說(shuō)了。

json序列化忽略空值字段 使用json.Marshal進(jìn)行序列化時(shí)不會(huì)忽略struct中的空值(這里說(shuō)的空值包含空字符串和nil),默認(rèn)輸出字段的類(lèi)型零值(string類(lèi)型零值是"",指針類(lèi)型的零值是nil),如果我們想在序列化時(shí)忽略掉這些沒(méi)有值的字段時(shí),可以在結(jié)構(gòu)體標(biāo)簽中中添加omitempty tag。

type Item struct{
  Id uint32 `json:"id"`
  Name string `json: "name,omitempty"`
  Password string `json: "-"`
}

這里說(shuō)一下,在Java里類(lèi)型分為基本類(lèi)型和包裝類(lèi)型,Java類(lèi)初始化的時(shí)候?qū)傩詾榛绢?lèi)型如果沒(méi)有賦予初始值,默認(rèn)值是0。包裝類(lèi)型聲明時(shí)沒(méi)有賦值的話(huà)的初始值為null。Go中初始化時(shí)沒(méi)有賦值的變量的默認(rèn)值如下:

  • 布爾類(lèi)型的默認(rèn)為false
  • 數(shù)值類(lèi)型的默認(rèn)為0
  • 字符串類(lèi)型的默認(rèn)為空字符串""
  • 指針類(lèi)型、函數(shù)、接口、切片、通道和map默認(rèn)值為nil

這樣看來(lái)Java和Go這個(gè)場(chǎng)景下處理方式,有相似和不同之處,大家開(kāi)發(fā)的時(shí)候要注意,由Java轉(zhuǎn)Go的同學(xué)開(kāi)發(fā)時(shí),千萬(wàn)別搞混了。

短變量聲明

在強(qiáng)類(lèi)型語(yǔ)言中,聲明一個(gè)變量都需要指定變量的類(lèi)型。可能語(yǔ)言的開(kāi)發(fā)者覺(jué)得這樣做對(duì)開(kāi)發(fā)者不太友好,就搞了個(gè)變量聲明不用指定類(lèi)型的語(yǔ)法糖,其實(shí)這個(gè)玩意說(shuō)起來(lái)就是類(lèi)型推導(dǎo)(Java8之后的版本貌似已經(jīng)有了),開(kāi)發(fā)者只管定義變量,類(lèi)型由語(yǔ)言編譯器來(lái)處理。

a := 10
#等用于
var a int = 10
#或者是
b:=fucName()

怎么說(shuō)呢?這樣有好處也有壞處,定義變量的人省事了,使用變量的人可能就懵逼了。就像這種場(chǎng)景b:=fucName(),這個(gè) 變量b是啥類(lèi)型,這個(gè)時(shí)候你只能點(diǎn)擊函數(shù)內(nèi),看函數(shù)的返回值類(lèi)型是啥,才能確定變量b是啥類(lèi)型。

我之前寫(xiě)過(guò)幾年的PHP,后來(lái)轉(zhuǎn)了Java,再到現(xiàn)在寫(xiě)Go。我發(fā)現(xiàn)各種開(kāi)發(fā)語(yǔ)言都在進(jìn)步,而且還相互模仿,PHP中函數(shù)之前不用指定形參類(lèi)型,PHP8中好像可以指定形參類(lèi)型了??傊褪菑?qiáng)弱類(lèi)型的語(yǔ)言在相互靠攏。

另類(lèi)的返回值

在Go語(yǔ)言中,允許您使用return語(yǔ)句從一個(gè)函數(shù)返回多個(gè)值。換句話(huà)說(shuō),在函數(shù)中,單個(gè)return語(yǔ)句可以返回多個(gè)值。返回值的類(lèi)型類(lèi)似于參數(shù)列表中定義的參數(shù)的類(lèi)型。

func func1(a string, b int) int {
   fmt.Println("func1------------")
   fmt.Println("a1 = ", a)
   fmt.Println("b1 = ", b)

   c := 100

   return c
}

可以這樣寫(xiě):返回多個(gè)返回值,形參命名

func func2(a string, b int) (int, int) {
	fmt.Println("func2------------")
	fmt.Println("a2 = ", a)
	fmt.Println("b2 = ", b)

	return 12, 33
}

可以這樣寫(xiě):返回多個(gè)返回值,形參匿名

func func3(a string, b int) (int, int) {
   fmt.Println("func3------------")
   fmt.Println("a2 = ", a)
   fmt.Println("b2 = ", b)

   return 12, 33
}

如果一個(gè)函數(shù)要返回多個(gè)值,在Java中可以使用定義一個(gè)新的類(lèi)來(lái)承載返回值,或者偷個(gè)懶使用map來(lái)接也是可以的。go支持多個(gè)返回值就我個(gè)人來(lái)說(shuō)還是支持的。其實(shí)說(shuō)到這里,多個(gè)返回值的各種形式都能理解。直到有一天我在翻看gorm的Open方法源碼發(fā)現(xiàn)了奇怪的地方,代碼位置信息:gorm.io/gorm@v1.23.4/gorm.go:116 ,節(jié)選部分代碼如下:

func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
	config := &Config{}

if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
		if err = d.Apply(config); err != nil {
			return
		}
	}
	# 省略此處無(wú)用代碼
	db = &DB{Config: config, clone: 1}

	db.callbacks = initializeCallbacks(db)

    # 省略此處無(wú)用代碼
	preparedStmt := &PreparedStmtDB{
		ConnPool:    db.ConnPool,
		Stmts:       map[string]Stmt{},
		Mux:         &sync.RWMutex{},
		PreparedSQL: make([]string, 0, 100),
	}
	db.cacheStore.Store(preparedStmtDBKey, preparedStmt)

    # 省略此處無(wú)用代碼
	db.Statement = &Statement{
		DB:       db,
		ConnPool: db.ConnPool,
		Context:  context.Background(),
		Clauses:  map[string]clause.Clause{},
	}
    # 省略此處無(wú)用代碼

	return
}

這就是文章開(kāi)頭提到的讓人懵逼的語(yǔ)法糖,我當(dāng)時(shí)看到這段代碼時(shí),我心中暗想這個(gè)是什么TM操作,竟然這樣也行,這樣竟然沒(méi)有報(bào)錯(cuò)…… 我來(lái)點(diǎn)出其中的問(wèn)題,就是return關(guān)鍵字處并沒(méi)有返回dberror變量。我把上述代碼在簡(jiǎn)化一下,用最簡(jiǎn)單的方式列出來(lái),如下:

func func4(a string, b int) (r1 int, r2 int) {
	fmt.Println("func4------------")
	//r1 r2輸入fool3的形參,初始化默認(rèn)的值是0
	//r1 r2 作用域空間是 func4 整個(gè)函數(shù)體的{}空間
	fmt.Println("r1 = ", r1)
	fmt.Println("r2 = ", r2)
	r1 = b * 2
	r2 = 2000

	return
}

上述這種方式其實(shí)本質(zhì)上來(lái)說(shuō)是和前面幾種方式一樣,只是在不知道這種約定的話(huà),會(huì)讓人難以理解。知道這個(gè)算是Go中的小tips之后,咱也不知道Go為啥要這么做,只是覺(jué)得有點(diǎn)懵,我只是覺(jué)得在Java中絕對(duì)不會(huì)出現(xiàn)這種情況。但是在Go中也許是設(shè)計(jì)Go的大佬們覺(jué)得這樣做可以省掉聲明變量r1r2的時(shí)間,畢竟大佬們的時(shí)間都很寶貴。

總結(jié)

本文介紹了一些Go語(yǔ)言中的語(yǔ)法糖,當(dāng)然并不全面,應(yīng)該還有其他的沒(méi)有介紹,希望大家能夠看完本篇文章后,能了解并掌握,并能在實(shí)際開(kāi)發(fā)中運(yùn)用到,當(dāng)然其中的函數(shù)多返回值的懵逼寫(xiě)法,就由大家自行判斷是用還是不用了。

以上就是一起聊聊Go語(yǔ)言中的語(yǔ)法糖的使用的詳細(xì)內(nèi)容,更多關(guān)于Go語(yǔ)言 語(yǔ)法糖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言中Goroutine的設(shè)置方式

    Go語(yǔ)言中Goroutine的設(shè)置方式

    這篇文章介紹了Go語(yǔ)言中Goroutine的設(shè)置方式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Go語(yǔ)言{}大括號(hào)的特殊用法實(shí)例探究

    Go語(yǔ)言{}大括號(hào)的特殊用法實(shí)例探究

    這篇文章主要為大家介紹了Go語(yǔ)言{}大括號(hào)的特殊用法實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢(xún)的方法

    Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢(xún)的方法

    這篇文章主要介紹了Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢(xún)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 深入探究Go語(yǔ)言從反射到元編程的實(shí)踐與探討

    深入探究Go語(yǔ)言從反射到元編程的實(shí)踐與探討

    反射和元編程是一些高級(jí)編程概念,它們使開(kāi)發(fā)者能夠在運(yùn)行時(shí)檢查、修改并控制程序的行為,了解反射和元編程的工作方式可以幫助我們更好地理解Go,以及如何在需要的時(shí)候高效地使用它們,文章中介紹的非常詳細(xì),感興趣的同學(xué)可以參考下
    2023-05-05
  • Go語(yǔ)言操作redis用法實(shí)例

    Go語(yǔ)言操作redis用法實(shí)例

    這篇文章主要介紹了Go語(yǔ)言操作redis用法,實(shí)例分析了Go語(yǔ)言操作redis的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Go語(yǔ)言中的變量和常量

    Go語(yǔ)言中的變量和常量

    這篇文章介紹了Go語(yǔ)言中的變量和常量,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Go通過(guò)不變性?xún)?yōu)化程序詳解

    Go通過(guò)不變性?xún)?yōu)化程序詳解

    這篇文章主要為大家介紹了Go通過(guò)不變性?xún)?yōu)化程序?qū)嵗斀猓行枰呐笥芽梢越梃b參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 使用go操作redis的有序集合(zset)

    使用go操作redis的有序集合(zset)

    這篇文章主要介紹了使用go操作redis的有序集合(zset),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go語(yǔ)言數(shù)據(jù)類(lèi)型之字符串string

    go語(yǔ)言數(shù)據(jù)類(lèi)型之字符串string

    這篇文章介紹了go語(yǔ)言數(shù)據(jù)類(lèi)型之字符串string,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Golang中切片的用法與本質(zhì)詳解

    Golang中切片的用法與本質(zhì)詳解

    Go的切片類(lèi)型為處理同類(lèi)型數(shù)據(jù)序列提供一個(gè)方便而高效的方式,下面這篇文章就來(lái)給大家介紹了關(guān)于Golang中切片的用法與本質(zhì)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-07-07

最新評(píng)論