Go語(yǔ)言的常量、枚舉、作用域示例詳解
常量
常量類(lèi)似于變量,但其初始值不能更改。在需要代碼運(yùn)行時(shí)保持不變的值的情況下,使用常量非常有用。雖然可以將這些值硬編碼到代碼中以實(shí)現(xiàn)類(lèi)似效果,但經(jīng)驗(yàn)表明,雖然這些值在運(yùn)行時(shí)不需要更改,但將來(lái)可能需要更改。如果發(fā)生這種情況,追蹤和修復(fù)所有硬編碼的值可能是一項(xiàng)繁瑣且容易出錯(cuò)的任務(wù)。使用常量可以節(jié)省大量的后續(xù)維護(hù)工作。
常量聲明類(lèi)似于 var 語(yǔ)句。定義常量時(shí),必須指定初始值。類(lèi)型是可選的,如果省略,類(lèi)型將會(huì)被推斷。初始值可以是文字值或簡(jiǎn)單的表達(dá)式,并且可以使用其他常量的值。與 var 一樣,可以在一個(gè)語(yǔ)句中聲明多個(gè)常量。以下是常量聲明的語(yǔ)法:
const <name> <type> = <value> const ( <name1> <type1> = <value1> <name2> <type2> = <value2> … <nameN> <typeN> = <valueN> )
練習(xí) 1.16 – 常量
在這個(gè)練習(xí)中,我們遇到了一個(gè)性能問(wèn)題:我們的數(shù)據(jù)庫(kù)服務(wù)器太慢了。我們將創(chuàng)建一個(gè)自定義內(nèi)存緩存。我們會(huì)使用 Go 的 map 集合類(lèi)型作為緩存。緩存中可以存儲(chǔ)的項(xiàng)目數(shù)量有一個(gè)全局限制。我們將使用一個(gè) map 來(lái)幫助跟蹤緩存中的項(xiàng)目數(shù)量。我們需要緩存兩種類(lèi)型的數(shù)據(jù):書(shū)籍和 CD。兩者都使用 ID,因此我們需要一種方法來(lái)區(qū)分共享緩存中的兩種類(lèi)型的項(xiàng)目。我們需要一種方法來(lái)設(shè)置和獲取緩存中的項(xiàng)目。
我們將設(shè)置緩存中的最大項(xiàng)目數(shù)量。我們還將使用常量添加前綴,以區(qū)分書(shū)籍和 CD。讓我們開(kāi)始吧:
創(chuàng)建一個(gè)新的文件夾,并在其中添加一個(gè) main.go 文件。
在 main.go 文件的頂部添加 main 包名:
package main
導(dǎo)入我們需要的包:
import "fmt"
創(chuàng)建一個(gè)表示全局限制大小的常量:
const GlobalLimit = 100
創(chuàng)建一個(gè) MaxCacheSize 常量,它是全局限制大小的 10 倍:
const MaxCacheSize int = 10 * GlobalLimit
創(chuàng)建我們的緩存前綴:
const ( CacheKeyBook = "book_" CacheKeyCD = "cd_")
聲明一個(gè) map 類(lèi)型的變量,用于存儲(chǔ)緩存,其中鍵和值都是字符串類(lèi)型:
var cache map[string]string
創(chuàng)建一個(gè)從緩存中獲取項(xiàng)目的函數(shù):
func cacheGet(key string) string {
return cache[key]
}創(chuàng)建一個(gè)在緩存中設(shè)置項(xiàng)目的函數(shù):
func cacheSet(key, val string) {在這個(gè)函數(shù)中,檢查 MaxCacheSize 常量,防止緩存超過(guò)這個(gè)大小:
if len(cache)+1 >= MaxCacheSize {
return
}
cache[key] = val
}創(chuàng)建一個(gè)從緩存中獲取書(shū)籍的函數(shù):
func GetBook(isbn string) string {使用書(shū)籍緩存前綴創(chuàng)建一個(gè)唯一的鍵:
return cacheGet(CacheKeyBook + isbn) }
創(chuàng)建一個(gè)將書(shū)籍添加到緩存中的函數(shù):
func SetBook(isbn string, name string) {使用書(shū)籍緩存前綴創(chuàng)建一個(gè)唯一的鍵:
cacheSet(CacheKeyBook+isbn, name) }
創(chuàng)建一個(gè)從緩存中獲取 CD 數(shù)據(jù)的函數(shù):
func GetCD(sku string) string {使用 CD 緩存前綴創(chuàng)建一個(gè)唯一的鍵:
cacheSet(CacheKeyCD+sku, title) }
創(chuàng)建一個(gè)將 CD 添加到共享緩存中的函數(shù):
func SetCD(sku string, title string) {使用 CD 緩存前綴常量為共享緩存構(gòu)建一個(gè)唯一的鍵:
cacheSet(CacheKeyCD+sku, title) }
創(chuàng)建 main() 函數(shù):
func main() {通過(guò)創(chuàng)建一個(gè) map 值來(lái)初始化緩存:
cache = make(map[string]string) }
將一本書(shū)添加到緩存中:
SetBook("1234-5678", "Get Ready To Go")將 CD 添加到緩存中:
SetCD("1234-5678", "Get Ready To Go Audio Book")從緩存中獲取并打印那本書(shū):
fmt.Println("Book :", GetBook("1234-5678"))從緩存中獲取并打印那張 CD:
fmt.Println("CD :", GetCD("1234-5678"))關(guān)閉 main() 函數(shù):
}
保存文件。然后,在新文件夾中運(yùn)行:
go run .
預(yù)期輸出
在這個(gè)練習(xí)中,我們使用常量來(lái)定義在代碼運(yùn)行時(shí)不需要更改的值。我們用不同的語(yǔ)法選項(xiàng)聲明了常量,有的指定了類(lèi)型,有的則沒(méi)有。我們既聲明了單個(gè)常量,也在一個(gè)語(yǔ)句中聲明了多個(gè)常量。
接下來(lái),我們將查看與常量相關(guān)的變體,用于更緊密關(guān)聯(lián)的值。
枚舉
枚舉是一種定義固定值列表的方式,這些值都是相關(guān)的。雖然 Go 語(yǔ)言沒(méi)有內(nèi)置的枚舉類(lèi)型,但它提供了 iota 工具,讓我們可以使用常量定義自己的枚舉。接下來(lái),我們將探討如何使用 iota 來(lái)實(shí)現(xiàn)枚舉。
例如,在以下代碼中,我們將一周的天數(shù)定義為常量。這個(gè)代碼很適合使用 Go 的 iota 特性:
… const ( Sunday = 0 Monday = 1 Tuesday = 2 Wednesday = 3 Thursday = 4 Friday = 5 Saturday = 6 ) …
使用 iota,Go 會(huì)幫助我們管理這樣的列表。使用 iota,以下代碼等同于上面的代碼:
… const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday ) …
通過(guò) iota,我們可以自動(dòng)為枚舉分配值。使用 iota 使得創(chuàng)建和維護(hù)枚舉更加方便,特別是在你需要在代碼中間添加新值時(shí)。iota 是一個(gè)標(biāo)識(shí)符,指示 Go 編譯器從 0 開(kāi)始為第一個(gè)值分配,后續(xù)值每次遞增 1。在使用 iota 時(shí),順序是重要的。iota 還允許跳過(guò)值(使用 _),從不同的偏移量開(kāi)始,甚至使用更復(fù)雜的計(jì)算。
接下來(lái),我們將詳細(xì)了解 Go 的變量作用域規(guī)則以及這些規(guī)則如何影響代碼編寫(xiě)。
作用域
在 Go 中,所有變量都存在于一個(gè)作用域中。頂級(jí)作用域是包作用域。作用域可以包含子作用域。定義子作用域的方式有幾種;最簡(jiǎn)單的理解方式是,當(dāng)你看到 { 時(shí),表示你開(kāi)始了一個(gè)新的子作用域,而這個(gè)子作用域在遇到匹配的 } 時(shí)結(jié)束。父子關(guān)系是在代碼編譯時(shí)定義的,而不是在代碼運(yùn)行時(shí)。當(dāng)訪問(wèn)變量時(shí),Go 會(huì)查看變量定義的作用域。如果在當(dāng)前作用域找不到該變量,Go 會(huì)查看父作用域,然后是祖父作用域,一直到包作用域。當(dāng)找到匹配的變量時(shí),Go 會(huì)停止查找。如果沒(méi)有找到匹配的變量,則會(huì)報(bào)錯(cuò)。
換句話說(shuō),當(dāng)你的代碼使用一個(gè)變量時(shí),Go 需要確定該變量的定義位置。它從當(dāng)前代碼的作用域開(kāi)始查找。如果在該作用域內(nèi)找到一個(gè)變量定義,則停止查找并使用該變量定義。如果找不到變量定義,則開(kāi)始向上遍歷作用域棧,直到找到具有該名稱(chēng)的變量。這個(gè)查找過(guò)程基于變量名稱(chēng)。如果找到的變量名稱(chēng)匹配但類(lèi)型不正確,Go 會(huì)拋出錯(cuò)誤。
在以下示例中,我們定義了一個(gè) level 變量。無(wú)論在哪里使用 level,都會(huì)使用同一個(gè)變量:
package main
import "fmt"
var level = "pkg"
func main() {
fmt.Println("Main start :", level)
if true {
fmt.Println("Block start :", level)
funcA()
}
}
func funcA() {
fmt.Println("funcA start :", level)
}輸出結(jié)果如下:
Main start : pkg
Block start : pkg
funcA start : pkg
在這個(gè)示例中,我們創(chuàng)建了一個(gè) level 的影子變量。這個(gè)新的 level 變量與包作用域中的 level 變量沒(méi)有關(guān)系。當(dāng)我們?cè)趬K內(nèi)打印 level 時(shí),Go 運(yùn)行時(shí)會(huì)在 main 的作用域中找到 level 變量,并停止查找。這導(dǎo)致新變量覆蓋了包變量。你也可以看到它是一個(gè)不同的變量,因?yàn)樗念?lèi)型不同,變量在 Go 中不能改變類(lèi)型:
package main
import "fmt"
var level = "pkg"
func main() {
fmt.Println("Main start :", level)
// 創(chuàng)建一個(gè)影子變量
level := 42
if true {
fmt.Println("Block start :", level)
funcA()
}
fmt.Println("Main end :", level)
}
func funcA() {
fmt.Println("funcA start :", level)
}輸出結(jié)果如下:
Main start : pkg
Block start : 42
funcA start : pkg
Main end : 42
Go 的靜態(tài)作用域解析在調(diào)用 funcA 時(shí)發(fā)揮作用。因此,當(dāng) funcA 運(yùn)行時(shí),它仍然看到包作用域中的 level 變量。作用域解析不考慮 funcA 的調(diào)用位置。
你不能訪問(wèn)子作用域中定義的變量:
package main
import "fmt"
func main() {
{
level := "Nest 1"
fmt.Println("Block end :", level)
}
// 錯(cuò)誤:未定義: level
//fmt.Println("Main end :", level)
}到此這篇關(guān)于Go語(yǔ)言的常量、枚舉、作用域的文章就介紹到這了,更多相關(guān)Go語(yǔ)言的常量枚舉作用域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GoZero實(shí)現(xiàn)數(shù)據(jù)庫(kù)MySQL單例模式連接的簡(jiǎn)單示例
在 GoZero 框架中實(shí)現(xiàn)數(shù)據(jù)庫(kù)的單例連接可以通過(guò)以下步驟來(lái)完成,GoZero 使用 gorm 作為默認(rèn)的數(shù)據(jù)庫(kù)操作框架,接下來(lái)我會(huì)展示一個(gè)簡(jiǎn)單的單例模式實(shí)現(xiàn),需要的朋友可以參考下2025-02-02
go語(yǔ)言在請(qǐng)求http時(shí)加入自定義http header的方法
這篇文章主要介紹了go語(yǔ)言在請(qǐng)求http時(shí)加入自定義http header的方法,實(shí)例分析了Go語(yǔ)言http請(qǐng)求的原理與操作技巧,需要的朋友可以參考下2015-03-03
golang基礎(chǔ)之reflect反射的實(shí)現(xiàn)
Golang反射通過(guò)TypeOf/ValueOf實(shí)現(xiàn)接口與反射對(duì)象的轉(zhuǎn)換,可動(dòng)態(tài)獲取和修改值,本文主要介紹了golang基礎(chǔ)之reflect反射的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2025-06-06
Golang?手寫(xiě)一個(gè)簡(jiǎn)單的并發(fā)任務(wù)?manager
這篇文章主要介紹了Golang?手寫(xiě)一個(gè)簡(jiǎn)單的并發(fā)任務(wù)?manager,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
基于Golang構(gòu)建一個(gè)網(wǎng)絡(luò)漏洞掃描器
Go?語(yǔ)言非常適合網(wǎng)絡(luò)編程,它在設(shè)計(jì)時(shí)就考慮到了并發(fā)性,并且擁有出色的標(biāo)準(zhǔn)庫(kù),本文將詳細(xì)介紹如何使用?Go?語(yǔ)言創(chuàng)建一個(gè)簡(jiǎn)單且相當(dāng)可靠的網(wǎng)絡(luò)漏洞掃描器,感興趣的小伙伴可以了解下2025-11-11
go語(yǔ)言題解LeetCode1122數(shù)組的相對(duì)排序
這篇文章主要為大家介紹了go語(yǔ)言題解LeetCode1122數(shù)組的相對(duì)排序,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
如何使用工具自動(dòng)監(jiān)測(cè)SSL證書(shū)有效期并發(fā)送提醒郵件
本文介紹了如何開(kāi)發(fā)一個(gè)工具,用于每日檢測(cè)SSL證書(shū)剩余有效天數(shù)并通過(guò)郵件發(fā)送提醒,工具基于命令行,通過(guò)SMTP協(xié)議發(fā)送郵件,需配置SMTP連接信息,本文還提供了配置文件樣例及代碼實(shí)現(xiàn),幫助用戶輕松部署和使用該工具2024-10-10

