Go語言中聲明變量(var)與常量(const)的完整指南
序言:今天開始學(xué)習(xí) Go 語言的 變量與常量,該文章會(huì)記錄一些相關(guān)的知識(shí)點(diǎn)和案例。
變量
定義
用于存儲(chǔ)程序運(yùn)行時(shí)可改變的數(shù)據(jù)
聲明方式
| 方式 | 語法 | 適用場景 | 示例 |
|---|---|---|---|
| 標(biāo)準(zhǔn)聲明 | var 變量名 類型 = 表達(dá)式 | 顯式指定類型 或 需要零值初始化 | var age int = 25 |
| 類型推斷 | var 變量名 = 表達(dá)式 | 省略類型,由右側(cè)值推導(dǎo) | var age = 25 |
| 聲明賦值 | var 變量名 類型 變量名 = 表達(dá)式 | 省略類型,由右側(cè)值推導(dǎo)先聲明,后賦值 | var age intage = 25 |
| 短變量聲明 | 變量名 := 表達(dá)式 | 函數(shù)內(nèi)部,最常用、最簡潔 | age := 25 |
| 多變量聲明 | var (變量1 類型1 = 值1 ...) var 變量1,變量2 = 值1,值2 ) | 批量聲明,常用于包級(jí)別 | var (age int = 25; name string = "windy")var a, b = 1,2 |
示例:標(biāo)準(zhǔn)聲明
package main
import "fmt"
func main() {
var age int = 25
fmt.Println(age)
}
輸出:25
這種聲明方式雖然很清晰明了,但對(duì)我來說有點(diǎn)麻煩。代碼敲多了的時(shí)候,是不會(huì)考慮這種,因?yàn)橛悬c(diǎn)累腦費(fèi)眼,所以優(yōu)先于簡潔的方式。
示例:類型推斷
package main
import "fmt"
func main() {
var age = 25
fmt.Println(age)
}
輸出:25
這種聲明方式相對(duì)于第一個(gè)來說簡單了些,我一般用于全局變量(看情況進(jìn)行初始化),例如存儲(chǔ)驗(yàn)證碼。
示例:聲明賦值
package main
import "fmt"
func main() {
var age int
age = 25
fmt.Println(age)
}
輸出:25
這種聲明方式乍一看比第一個(gè)還復(fù)雜,但我用的比較多,例如初始化結(jié)構(gòu)體,然后根據(jù)需求挨個(gè)進(jìn)行賦值。
示例:短變量聲明
package main
import "fmt"
func main() {
age := 25
fmt.Println(age)
}
輸出:25
這種聲明方式最簡潔,我用的也多,例如調(diào)用函數(shù)的時(shí)接收結(jié)果( res, _ := myFun() )。
示例:多變量聲明
import "fmt"
func main() {
var (
age int = 25
name string = "windy"
)
fmt.Println(age, name)
var a, b = 1, 2
fmt.Println(a, b)
}
// 也可以刪除類型,結(jié)果是一樣的
輸出:
25 windy
12
這種聲明方式我基本上就是了解了解,就沒用過。
短變量聲明的一些小細(xì)節(jié)
- 作用域限制: 只能用在函數(shù)內(nèi)部,不能用于包級(jí)別
- 重復(fù)聲明規(guī)則: 在同一代碼塊中,若左側(cè)變量名至少有一個(gè)是新變量,則允許對(duì)舊變量使用
:=(此時(shí)舊變量的行為是賦值而非重新聲明)。 - 特殊的空白標(biāo)識(shí)符 : 如果函數(shù)的返回值有些不需要,可以給變量取名為下劃線
_。
示例:重復(fù)聲明規(guī)則
運(yùn)行成功
package main
import "fmt"
func myFunOne() (string, error) {
return "Hello", nil
}
func myFunTwo() (string, error) {
return "world", nil
}
func main() {
one, err := myFunOne() // 聲明 a 和 err
two, err := myFunTwo() // 聲明 b,對(duì) err 賦值(合法,因?yàn)?b 是新的)
fmt.Println(one, two, err)
}
輸出:Hello world <nil>
沒編譯時(shí)就提示報(bào)錯(cuò)
package main
import "fmt"
func myFunOne() (string, error) {
return "Hello", nil
}
func myFunTwo() (string, error) {
return "world", nil
}
func main() {
one, err := myFunOne() // 聲明 a 和 err
one, err := myFunTwo() // 報(bào)錯(cuò),左側(cè)無新變量
fmt.Println(one, err)
}
// 報(bào)錯(cuò)提示:No new variables on the left side of ':=', Replace with'='
// 左邊沒有新變量,直接用 = 即可(會(huì)覆蓋之前的值)
特殊的空白標(biāo)識(shí)符
在 Go 的短變量聲明 := 中,下劃線 _ 是一個(gè)特殊的空白標(biāo)識(shí)符。它用于占位,表示主動(dòng)忽略某個(gè)返回值或聲明項(xiàng)。關(guān)于它的使用,有幾個(gè)關(guān)鍵點(diǎn)需要特別注意:
_ 不算“新變量”,不參與重復(fù)聲明規(guī)則的判定
- 在
:=左側(cè),只要出現(xiàn)至少一個(gè)非_的新變量名,聲明就是合法的。 _可以被重復(fù)使用任意多次,它不會(huì)導(dǎo)致編譯錯(cuò)誤,也不會(huì)被視為新的有效變量。
_ 無法被讀取,只用于占位丟棄值
_本質(zhì)上不綁定任何值。你不能試圖讀取或使用它。- 它最常見的場景是處理函數(shù)的多返回值,比如忽略
error。
_ 聲明的變量 “未使用” 不會(huì)報(bào)錯(cuò):Go 編譯器強(qiáng)制要求聲明的非 _ 變量必須被使用。但 _ 是唯一的例外,它可以被多次 “聲明” 且永不使用。
_ 不能用于常量或類型聲明:_ 僅在 變量聲明 和 賦值 場景作為占位符,不能用于 const 或 type 定義。
在 := 中左側(cè)全是 _ 是語法錯(cuò)誤
- 即使你只是為了調(diào)用一個(gè)函數(shù)并忽略其所有返回值,也不能寫
_ := myFun()。 - 正確做法是 直接調(diào)用 或 使用普通賦值(非短聲明):
記?。?strong>把 _ 當(dāng)成黑洞,它只為滿足語法結(jié)構(gòu)而存在,不參與任何變量計(jì)數(shù)的邏輯。
常量
定義
編譯時(shí)確定、運(yùn)行時(shí)不改變的值
聲明方式
| 方式 | 語法 | 示例 |
|---|---|---|
| 標(biāo)準(zhǔn)聲明 | const 常量名 類型 = 表達(dá)式 | const Age int = 25 |
| 類型推斷 | const 常量名 = 表達(dá)式 | const Age = 25 |
| 多常量聲明 | const (常量1 類型1 = 值1 ...) | const (Age int = 25; Name string = "windy") |
| 隱式重復(fù) | 多常量聲明塊中省略右值時(shí)自動(dòng)沿用上一行表達(dá)式 | const ( A = 1; B; C ) |
示例:標(biāo)準(zhǔn)聲明
package main
import "fmt"
func main() {
const age int = 25
fmt.Println(age)
}
輸出:25
這種聲明方式雖然有點(diǎn)麻煩,但很清晰明了。一般來說,常量定義的數(shù)量比變量少很多,且大多數(shù)都定義在函數(shù)外,調(diào)用常量的時(shí)候能一下子知道是什么類型的會(huì)比較好。
示例:類型推斷
package main
import "fmt"
func main() {
const age = 25
fmt.Println(age)
}
輸出:25
這種聲明方式個(gè)人習(xí)慣上不常使用,推薦第一種。
示例:多常量聲明
package main
import "fmt"
func main() {
const (
age int = 25
name string = "windy"
)
fmt.Println(age, name)
}
// 也可以刪除類型,結(jié)果是一樣的
輸出:25 windy
這種聲明方式一般在定義差不多含義的常量的時(shí)候使用,比如返回碼( 200,404,500 等 )。
示例:隱式重復(fù)
package main
import "fmt"
func main() {
const (
Apple = "fruit"
Banana // = "fruit"
Cherry // = "fruit"
)
// Banana 和 Cherry 的值都是 "fruit"
fmt.Println(Apple, Banana, Cherry)
}
輸出: fruit fruit fruit
基本上沒用過這種聲明方式,不知道以后會(huì)不會(huì)有用得到的場景
命名規(guī)則
標(biāo)識(shí)符語法規(guī)則(強(qiáng)制)
- 由字母(Unicode 字母)、數(shù)字、下劃線
_組成。 - 不能以數(shù)字開頭。
- 區(qū)分大小寫,例如
Name和name是不同的。 - 不能是 Go 語言的 關(guān)鍵字,例如
func、var、const、if、for等。 - 下劃線
_是特殊的空白標(biāo)識(shí)符,不能作為常規(guī)變量名使用(聲明即丟棄)。
導(dǎo)出規(guī)則(可見性控制)
Go 沒有 public/private 關(guān)鍵字,而是用 首字母的大小寫 控制包外可見性:
| 首字母 | 可見性 | 術(shù)語 |
|---|---|---|
| 大寫 | 包外可訪問 | Exported (導(dǎo)出標(biāo)識(shí)符) |
| 小寫 或 下劃線 | 僅包內(nèi)可訪問 | Unexported (未導(dǎo)出標(biāo)識(shí)符) |
命名風(fēng)格約定(非強(qiáng)制,但強(qiáng)烈推薦)
Go 社區(qū)遵循一套統(tǒng)一的命名風(fēng)格,保證了代碼的可讀性和一致性:
| 對(duì)象類型 | 風(fēng)格 | 示例 |
|---|---|---|
| 變量 | 駝峰式 (camelCase) | userCount, httpRequest |
| 常量 | 駝峰式 (PascalCase 或 camelCase) | MaxRetries (導(dǎo)出), defaultPort (未導(dǎo)出) |
| 函數(shù) / 方法 | 駝峰式 | GetUser, parseData |
| 類型名 | 駝峰式,首字母大寫(導(dǎo)出) | UserService, httpClient (未導(dǎo)出) |
| 包名 | 全小寫,簡短,無下劃線 | time, httputil, strings |
| 接口名 | 通常以 er 結(jié)尾(單方法接口) | Reader, Writer, Closer |
| 縮寫詞 | 全大寫或全小寫,保持一致 | HTTPServer (或 httpServer),不能寫成 HttpServer |
特殊命名約定 與 注意點(diǎn)
_(空白標(biāo)識(shí)符) :用于占位忽略值。_test后綴:文件名xxx_test.go是測(cè)試文件,包名通常是xxx_test或原包名。- 內(nèi)部包
internal:路徑中包含/internal/的包只能被其父目錄下的包導(dǎo)入,是一種強(qiáng)制的可見性控制。 - 避免無意義的包名:如
util、common、helper,盡量使用描述功能的具體名字。
使用范圍(作用域 Scope)
作用域決定了標(biāo)識(shí)符( 變量名、常量名 )在代碼中的可見范圍。Go 的作用域是詞法作用域(靜態(tài)作用域),由代碼塊 {} 界定。
作用域?qū)蛹?jí)(從大到小)
| 級(jí)別 | 聲明位置 | 可見范圍 |
|---|---|---|
| 全局作用域 | 所有函數(shù)之外 | 整個(gè)包(package)內(nèi) |
| 包級(jí)私有 | 函數(shù)外,首字母小寫 | 僅當(dāng)前包 |
| 包級(jí)導(dǎo)出 | 函數(shù)外,首字母大寫 | 當(dāng)前包 + 其他導(dǎo)入此包的包 |
| 函數(shù)作用域 | 函數(shù)體內(nèi)任何位置 | 該函數(shù)體內(nèi)(從聲明點(diǎn)到函數(shù)結(jié)束) |
| 塊作用域 | if、for、switch 的 {} 內(nèi) | 僅該花括號(hào)塊內(nèi) |
作用域遮蔽 (Shadowing)
內(nèi)層作用域聲明的變量若與外層同名,會(huì) 遮蔽 外層變量。這是 Go 代碼中非常常見的坑。
示例
package main
import "fmt"
var myName = "true" // 包級(jí)變量
func main() {
fmt.Println(myName) // 輸出 true
// 在塊內(nèi)聲明同名變量,創(chuàng)建了新變量而非修改外層
if true {
var myName = "false"
fmt.Println(myName)
// 這個(gè) myName 是塊內(nèi)新變量,值為 false
}
fmt.Println(myName) // 仍然輸出 true,包級(jí)變量未被修改
}
輸出:
true
false
true
為了節(jié)省腦子,盡量不重名,如果實(shí)在不想思考其他切合的名字,就直接 name1,name2。
避免遮蔽的建議
- 使用
go vet的-shadow選項(xiàng)檢測(cè)(go vet -shadow ./...)。 - 在內(nèi)部作用域中,若意圖修改外層變量,直接使用賦值
=而非:=。
包級(jí)變量 與 常量 的初始化順序
- 在同一個(gè)包內(nèi),多個(gè)
.go文件中的包級(jí)變量按 文件名字母順序 初始化。 - 單個(gè)文件內(nèi),按聲明順序 從上到下 初始化。
- 若初始化表達(dá)式引用其他包級(jí)變量,Go 會(huì)處理依賴關(guān)系,禁止循環(huán)引用。
- 常量在編譯時(shí)求值,不依賴運(yùn)行時(shí)初始化順序。
以上就是Go語言中聲明變量(var)與常量(const)的完整指南的詳細(xì)內(nèi)容,更多關(guān)于Go聲明變量與常量的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
go并發(fā)實(shí)現(xiàn)素?cái)?shù)篩的代碼
這篇文章主要介紹了go并發(fā)實(shí)現(xiàn)素?cái)?shù)篩的代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
go使用errors.Wrapf()代替log.Error()方法示例
這篇文章主要為大家介紹了go使用errors.Wrapf()代替log.Error()的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Go 泛型Generics實(shí)戰(zhàn)場景示例
本文給大家介紹Go泛型Generics實(shí)戰(zhàn)場景示例,本文通過多種場景給大家詳細(xì)講解,感興趣的朋友跟隨小編一起看看吧2026-01-01
Go 代碼規(guī)范錯(cuò)誤處理示例經(jīng)驗(yàn)總結(jié)
這篇文章主要為大家介紹了Go 代碼規(guī)范錯(cuò)誤處理示例實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

