Go語言的常量、枚舉、作用域示例詳解
常量
常量類似于變量,但其初始值不能更改。在需要代碼運行時保持不變的值的情況下,使用常量非常有用。雖然可以將這些值硬編碼到代碼中以實現(xiàn)類似效果,但經(jīng)驗表明,雖然這些值在運行時不需要更改,但將來可能需要更改。如果發(fā)生這種情況,追蹤和修復所有硬編碼的值可能是一項繁瑣且容易出錯的任務。使用常量可以節(jié)省大量的后續(xù)維護工作。
常量聲明類似于 var 語句。定義常量時,必須指定初始值。類型是可選的,如果省略,類型將會被推斷。初始值可以是文字值或簡單的表達式,并且可以使用其他常量的值。與 var 一樣,可以在一個語句中聲明多個常量。以下是常量聲明的語法:
const <name> <type> = <value> const ( <name1> <type1> = <value1> <name2> <type2> = <value2> … <nameN> <typeN> = <valueN> )
練習 1.16 – 常量
在這個練習中,我們遇到了一個性能問題:我們的數(shù)據(jù)庫服務器太慢了。我們將創(chuàng)建一個自定義內(nèi)存緩存。我們會使用 Go 的 map 集合類型作為緩存。緩存中可以存儲的項目數(shù)量有一個全局限制。我們將使用一個 map 來幫助跟蹤緩存中的項目數(shù)量。我們需要緩存兩種類型的數(shù)據(jù):書籍和 CD。兩者都使用 ID,因此我們需要一種方法來區(qū)分共享緩存中的兩種類型的項目。我們需要一種方法來設置和獲取緩存中的項目。
我們將設置緩存中的最大項目數(shù)量。我們還將使用常量添加前綴,以區(qū)分書籍和 CD。讓我們開始吧:
創(chuàng)建一個新的文件夾,并在其中添加一個 main.go 文件。
在 main.go 文件的頂部添加 main 包名:
package main
導入我們需要的包:
import "fmt"
創(chuàng)建一個表示全局限制大小的常量:
const GlobalLimit = 100
創(chuàng)建一個 MaxCacheSize 常量,它是全局限制大小的 10 倍:
const MaxCacheSize int = 10 * GlobalLimit
創(chuàng)建我們的緩存前綴:
const ( CacheKeyBook = "book_" CacheKeyCD = "cd_")
聲明一個 map 類型的變量,用于存儲緩存,其中鍵和值都是字符串類型:
var cache map[string]string
創(chuàng)建一個從緩存中獲取項目的函數(shù):
func cacheGet(key string) string { return cache[key] }
創(chuàng)建一個在緩存中設置項目的函數(shù):
func cacheSet(key, val string) {
在這個函數(shù)中,檢查 MaxCacheSize 常量,防止緩存超過這個大?。?/p>
if len(cache)+1 >= MaxCacheSize { return } cache[key] = val }
創(chuàng)建一個從緩存中獲取書籍的函數(shù):
func GetBook(isbn string) string {
使用書籍緩存前綴創(chuàng)建一個唯一的鍵:
return cacheGet(CacheKeyBook + isbn) }
創(chuàng)建一個將書籍添加到緩存中的函數(shù):
func SetBook(isbn string, name string) {
使用書籍緩存前綴創(chuàng)建一個唯一的鍵:
cacheSet(CacheKeyBook+isbn, name) }
創(chuàng)建一個從緩存中獲取 CD 數(shù)據(jù)的函數(shù):
func GetCD(sku string) string {
使用 CD 緩存前綴創(chuàng)建一個唯一的鍵:
cacheSet(CacheKeyCD+sku, title) }
創(chuàng)建一個將 CD 添加到共享緩存中的函數(shù):
func SetCD(sku string, title string) {
使用 CD 緩存前綴常量為共享緩存構建一個唯一的鍵:
cacheSet(CacheKeyCD+sku, title) }
創(chuàng)建 main() 函數(shù):
func main() {
通過創(chuàng)建一個 map 值來初始化緩存:
cache = make(map[string]string) }
將一本書添加到緩存中:
SetBook("1234-5678", "Get Ready To Go")
將 CD 添加到緩存中:
SetCD("1234-5678", "Get Ready To Go Audio Book")
從緩存中獲取并打印那本書:
fmt.Println("Book :", GetBook("1234-5678"))
從緩存中獲取并打印那張 CD:
fmt.Println("CD :", GetCD("1234-5678"))
關閉 main() 函數(shù):
}
保存文件。然后,在新文件夾中運行:
go run .
預期輸出
在這個練習中,我們使用常量來定義在代碼運行時不需要更改的值。我們用不同的語法選項聲明了常量,有的指定了類型,有的則沒有。我們既聲明了單個常量,也在一個語句中聲明了多個常量。
接下來,我們將查看與常量相關的變體,用于更緊密關聯(lián)的值。
枚舉
枚舉是一種定義固定值列表的方式,這些值都是相關的。雖然 Go 語言沒有內(nèi)置的枚舉類型,但它提供了 iota 工具,讓我們可以使用常量定義自己的枚舉。接下來,我們將探討如何使用 iota 來實現(xiàn)枚舉。
例如,在以下代碼中,我們將一周的天數(shù)定義為常量。這個代碼很適合使用 Go 的 iota 特性:
… const ( Sunday = 0 Monday = 1 Tuesday = 2 Wednesday = 3 Thursday = 4 Friday = 5 Saturday = 6 ) …
使用 iota,Go 會幫助我們管理這樣的列表。使用 iota,以下代碼等同于上面的代碼:
… const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday ) …
通過 iota,我們可以自動為枚舉分配值。使用 iota 使得創(chuàng)建和維護枚舉更加方便,特別是在你需要在代碼中間添加新值時。iota 是一個標識符,指示 Go 編譯器從 0 開始為第一個值分配,后續(xù)值每次遞增 1。在使用 iota 時,順序是重要的。iota 還允許跳過值(使用 _),從不同的偏移量開始,甚至使用更復雜的計算。
接下來,我們將詳細了解 Go 的變量作用域規(guī)則以及這些規(guī)則如何影響代碼編寫。
作用域
在 Go 中,所有變量都存在于一個作用域中。頂級作用域是包作用域。作用域可以包含子作用域。定義子作用域的方式有幾種;最簡單的理解方式是,當你看到 { 時,表示你開始了一個新的子作用域,而這個子作用域在遇到匹配的 } 時結束。父子關系是在代碼編譯時定義的,而不是在代碼運行時。當訪問變量時,Go 會查看變量定義的作用域。如果在當前作用域找不到該變量,Go 會查看父作用域,然后是祖父作用域,一直到包作用域。當找到匹配的變量時,Go 會停止查找。如果沒有找到匹配的變量,則會報錯。
換句話說,當你的代碼使用一個變量時,Go 需要確定該變量的定義位置。它從當前代碼的作用域開始查找。如果在該作用域內(nèi)找到一個變量定義,則停止查找并使用該變量定義。如果找不到變量定義,則開始向上遍歷作用域棧,直到找到具有該名稱的變量。這個查找過程基于變量名稱。如果找到的變量名稱匹配但類型不正確,Go 會拋出錯誤。
在以下示例中,我們定義了一個 level 變量。無論在哪里使用 level,都會使用同一個變量:
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) }
輸出結果如下:
Main start : pkg
Block start : pkg
funcA start : pkg
在這個示例中,我們創(chuàng)建了一個 level 的影子變量。這個新的 level 變量與包作用域中的 level 變量沒有關系。當我們在塊內(nèi)打印 level 時,Go 運行時會在 main 的作用域中找到 level 變量,并停止查找。這導致新變量覆蓋了包變量。你也可以看到它是一個不同的變量,因為它的類型不同,變量在 Go 中不能改變類型:
package main import "fmt" var level = "pkg" func main() { fmt.Println("Main start :", level) // 創(chuàng)建一個影子變量 level := 42 if true { fmt.Println("Block start :", level) funcA() } fmt.Println("Main end :", level) } func funcA() { fmt.Println("funcA start :", level) }
輸出結果如下:
Main start : pkg
Block start : 42
funcA start : pkg
Main end : 42
Go 的靜態(tài)作用域解析在調用 funcA 時發(fā)揮作用。因此,當 funcA 運行時,它仍然看到包作用域中的 level 變量。作用域解析不考慮 funcA 的調用位置。
你不能訪問子作用域中定義的變量:
package main import "fmt" func main() { { level := "Nest 1" fmt.Println("Block end :", level) } // 錯誤:未定義: level //fmt.Println("Main end :", level) }
到此這篇關于Go語言的常量、枚舉、作用域的文章就介紹到這了,更多相關Go語言的常量枚舉作用域內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Go語言基礎知識總結(語法、變量、數(shù)值類型、表達式、控制結構等)
這篇文章主要介紹了Go語言基礎知識總結(語法、變量、數(shù)值類型、表達式、控制結構等),本文匯總了Go語言的入門知識,需要的朋友可以參考下2014-10-10Go標準庫strconv實現(xiàn)string類型與其他基本數(shù)據(jù)類型之間轉換
這篇文章主要為大家介紹了Go標準庫strconv實現(xiàn)string類型與其他基本數(shù)據(jù)類型之間轉換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11