Go習(xí)慣用法(多值賦值短變量聲明賦值簡(jiǎn)寫(xiě)模式)基礎(chǔ)實(shí)例
1. 多值賦值
可以一次性聲明多個(gè)變量,并可以在聲明時(shí)賦值,而且可以省略類(lèi)型,但必須遵守一定的規(guī)則要求。
package main import "fmt" func main() { var x, y int // 相同類(lèi)型變量可以在末尾帶上類(lèi)型 var a, b int = 1, 2 var c, d = 3, 4 // 不帶類(lèi)型時(shí),編譯器自動(dòng)推斷 var ( // 不同類(lèi)型變量聲明和隱式初始化 e int f string ) var g int, e int = 6, 7 // 多賦值語(yǔ)句中每個(gè)變量后面不能都帶上類(lèi)型 fmt.Println("x ", x) fmt.Println("y ", y) fmt.Println("a ", a) fmt.Println("b ", b) fmt.Println("c ", c) fmt.Println("d ", d) fmt.Println("e ", e) fmt.Println("f ", f) }
有如下錯(cuò)誤:
.\main.go:14:14: syntax error: unexpected comma at end of statement
2. 短變量的聲明和賦值
Go
語(yǔ)言的語(yǔ)法允許多值短變量聲明和賦值的多個(gè)變量中,只要有一個(gè)是新變量就可以使用 :=
進(jìn)行賦值。
也就是說(shuō),在多值短變量的聲明和賦值時(shí), 至少有一個(gè)變量是新創(chuàng)建的局部變量,其他的變量可以復(fù)用以前的變量,不是新創(chuàng)建的變量執(zhí)行的僅僅是賦值。
package main import "fmt" func main() { var a int = 0 var b int = 0 a, b := 1, 2 fmt.Println("a ", a) fmt.Println("b ", b) }
會(huì)有以下錯(cuò)誤:
.\main.go:8:10: no new variables on left side of :=
要想通過(guò)編譯, a, b := 1, 2
至少一個(gè)變量是新定義的局部變量,如果在賦值語(yǔ)句 a, b := 1, 2
中已經(jīng)存在一個(gè)局部變量 a
,則賦值語(yǔ)句不會(huì)創(chuàng)建新的變量 a
, 而是使用 1 賦值給已經(jīng)聲明的局部變量。但是會(huì)創(chuàng)建新的變量 b
并給其賦值。
賦值操作符 =
和 :=
的區(qū)別:
=
不會(huì)聲明并創(chuàng)建新變量,而是在當(dāng)前賦值語(yǔ)句所在的作用域由內(nèi)向外逐層去搜尋變量,如果沒(méi)有搜索到相同的變量名,則報(bào)編譯錯(cuò)誤。:=
必須出現(xiàn)在函數(shù)或者類(lèi)型方法內(nèi)部。:=
至少要?jiǎng)?chuàng)建一個(gè)局部變量并初始化。
多值短變量聲明賦值 :=
的最佳使用場(chǎng)景是在錯(cuò)誤處理上。例如:
a, err := f() if err ! = nil { // do something } // 此時(shí) err 可以是已存在的 err 變量,只是重新賦值了 b, err := g()
3. 簡(jiǎn)寫(xiě)模式
Go
語(yǔ)言很多重復(fù)的引用或聲明可以用 ()
進(jìn)行簡(jiǎn)寫(xiě)。
import 多個(gè)包;
// 推薦寫(xiě)法 import ( "os" "fmt" ) // 不推薦寫(xiě)法 import "os" import "fmt"
多個(gè)變量聲明;
包中多個(gè)相關(guān)全局變量聲明時(shí),建議使用 ()
進(jìn)行合并聲明
// 推薦寫(xiě)法 var ( uploadStatus bool downStatus bool ) // 不推薦寫(xiě)法 var uploadStatus bool var uploadStatus bool
4. 多值返回函數(shù)
多值返回函數(shù)里如果有 error
或 bool
類(lèi)型的返回值,則應(yīng)該將 error
和 bool
作為最后一個(gè)返回值。這是一種編程風(fēng)格,沒(méi)有對(duì)錯(cuò)。
buffer.go:107: func (b *Buffer) tryGrowByReslice(n int) (int, bool) { buffer.go:335: func (b *Buffer) ReadByte() (byte , error) {
5. comma,ok 表達(dá)式
常見(jiàn)的幾個(gè) comma, ok 表達(dá)式用法有以下幾種情況:
獲取 map 值
獲取 map 中不存在鍵的值不會(huì)發(fā)生異常,而是會(huì)返回值類(lèi)型的零值,如果想確定 map 中是否存在某個(gè) key,則可以使用獲取 map 值的 comma, ok 語(yǔ)法。示例如下:
m := make(map[string] string) v, ok := m["camera"] if ok { Println("camera exist") } else { Println("camera not exist") }
讀取 chan 值
讀取已經(jīng)關(guān)閉的通道不會(huì)阻塞,也不會(huì)引起 panic, 而是一直返回該通道的零值,判斷通道關(guān)閉有兩種方法,一種是 comma, ok 表達(dá)式;另一種是通過(guò) range 循環(huán)迭代。
c := make(chan int) go func() { c <- 1 c <- 2 close(c) }() for { v, ok := <- c if ok { Println("v exist") } else { Println("v not exist") } } for v := range c { Println(v) }
類(lèi)型斷言
如果 map
查找、類(lèi)型斷言或通道接收出現(xiàn)在賦值語(yǔ)句的右邊,它們都可能會(huì)產(chǎn)生兩個(gè)結(jié)果,有一個(gè)額外的布爾結(jié)果表示操作是否成功:
v, ok = m[key] // map lookup v, ok = x.(T) // type assertion v, ok = <-ch // channel receive
注意:map
查找、類(lèi)型斷言或通道接收出現(xiàn)在賦值語(yǔ)句的右邊時(shí),并不一定是產(chǎn)生兩個(gè)結(jié)果,也可能只產(chǎn)生一個(gè)結(jié)果。對(duì)于只產(chǎn)生一個(gè)結(jié)果的情形, map
查找失敗時(shí)會(huì)返回零值,類(lèi)型斷言失敗時(shí)會(huì)發(fā)生運(yùn)行時(shí) panic
異常,通道接收失敗時(shí)會(huì)返回零值(阻塞不算是失?。@缦旅娴睦樱?/p>
v = m[key] // map查找,失敗時(shí)返回零值 v = x.(T) // type斷言,失敗時(shí)panic異常 v = <-ch // 管道接收,失敗時(shí)返回零值(阻塞不算是失?。? _, ok = m[key] // map返回2個(gè)值 _, ok = mm[""], false // map返回1個(gè)值 _ = mm[""] // map返回1個(gè)值
和變量聲明一樣,我們可以用下劃線空白標(biāo)識(shí)符_
來(lái)丟棄不需要的值。
_, err = io.Copy(dst, src) // 丟棄字節(jié)數(shù) _, ok = x.(T) // 只檢測(cè)類(lèi)型,忽略具體值
6. 傳值規(guī)則
Go
只有一種參數(shù)傳遞規(guī)則,那就是值拷貝,這種規(guī)則包括兩種含義:
函數(shù)參數(shù)傳遞時(shí)使用的是值拷貝。
實(shí)例賦值給接口變量,接口對(duì)實(shí)例的引用是值拷貝。
有時(shí)在明明是值拷貝的地方,結(jié)果卻修改了變量的內(nèi)容,有以下兩種情況:
直接傳遞的是指針。指針傳遞同樣是值拷貝,但指針和指針副本的值指向的地址是同一個(gè)地方,所以能修改實(shí)參值。
參數(shù)是復(fù)合數(shù)據(jù)類(lèi)型,這些復(fù)合數(shù)據(jù)類(lèi)型內(nèi)部有指針類(lèi)型的元素,此時(shí)參數(shù)的值拷貝并不影響指針的指向。
Go
復(fù)合類(lèi)型中 chan
、 map
、 slice
、 interface
內(nèi)部都是通過(guò)指針指向具體的數(shù)據(jù),這些類(lèi)型的變量在作為函數(shù)參數(shù)傳遞時(shí),實(shí)際上相當(dāng)于指針的副本。
package main import "fmt" func main() { var x, y int = 3, 5 fmt.Printf("befor swap x is %d\n", x) fmt.Printf("befor swapy is %d\n", y) x, y = swap_value(x, y) fmt.Printf("after swap x is %d\n", x) fmt.Printf("after swap y is %d\n", y) x, y = swap_reference(&x, &y) fmt.Printf("after swap_reference x is %d\n", x) fmt.Printf("after swap_reference y is %d\n", y) } func swap_value(x int, y int) (int, int) { var tmp int tmp = x x = y y = tmp return x, y } func swap_reference(x *int, y *int) (int, int) { var tmp int tmp = *x *x = *y *y = tmp return *x, *y }
輸出:
befor swap x is 3
befor swapy is 5
after swap x is 5
after swap y is 3
after swap_reference x is 3
after swap_reference y is 5
以上就是Go習(xí)慣用法(多值賦值短變量聲明賦值簡(jiǎn)寫(xiě)模式)基礎(chǔ)實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于Go多值賦值短變量聲明的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Go語(yǔ)言開(kāi)發(fā)中實(shí)現(xiàn)高性能的分布式日志收集的方法
本文介紹了在Go語(yǔ)言開(kāi)發(fā)中實(shí)現(xiàn)高性能分布式日志收集的關(guān)鍵步驟和考慮因素,包括日志生成與采集、日志傳輸、日志收集器的高性能網(wǎng)絡(luò)I/O、日志存儲(chǔ)與分析、監(jiān)控與告警系統(tǒng)、擴(kuò)展性與可維護(hù)性等方面,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-01-01gtoken替換jwt實(shí)現(xiàn)sso登錄的排雷避坑
這篇文章主要為大家介紹了gtoken替換jwt實(shí)現(xiàn)sso登錄的排雷避坑,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06golang使用正則表達(dá)式解析網(wǎng)頁(yè)
這篇文章主要介紹了golang使用正則表達(dá)式解析網(wǎng)頁(yè),需要的朋友可以參考下2015-03-03Golang實(shí)現(xiàn)四種負(fù)載均衡的算法(隨機(jī),輪詢等)
本文介紹了示例介紹了Golang 負(fù)載均衡的四種實(shí)現(xiàn),主要包括了隨機(jī),輪詢,加權(quán)輪詢負(fù)載,一致性hash,感興趣的小伙伴們可以參考一下2021-06-06go語(yǔ)言區(qū)塊鏈學(xué)習(xí)調(diào)用以太坊
這篇文章主要為大家介紹了go語(yǔ)言區(qū)塊鏈學(xué)習(xí)如何調(diào)用以太坊的示例實(shí)現(xiàn)過(guò)程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10Go語(yǔ)言中println和fmt.Println區(qū)別
本文主要介紹了Go語(yǔ)言中println和fmt.Println區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07文字解說(shuō)Golang Goroutine和線程的區(qū)別
goroutine 是 Go語(yǔ)言中的輕量級(jí)線程實(shí)現(xiàn),由 Go 運(yùn)行時(shí)(runtime)管理,使用每一個(gè) go 關(guān)鍵字將會(huì)額外開(kāi)啟一個(gè)新的協(xié)程 goroutine,今天通過(guò)本文給大家介紹下Golang Goroutine和線程的區(qū)別,感興趣的朋友一起看看吧2022-03-03golang實(shí)現(xiàn)java uuid的序列化方法
這篇文章主要介紹了golang實(shí)現(xiàn)java uuid的序列化方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09