當我第一次接觸 Go 時,我認為常數很簡單且有限——只是固定值,沒什麼花哨的。但隨著我深入研究,我發現它們非常多才多藝。是的,它們是固定值,但 Go 以靈活且高效的方式處理它們。非常酷。讓我們透過一些實際例子來看看這意味著什麼。
在 Go 中,常數通常是無類型的,直到您實際使用它們為止。它們具有預設類型,但可以分配給不同類型的變量,只要值合適即可。這使得它們以一種對於靜態類型語言來說不尋常的方式適應。
看起來是這樣的:
const x = 10 var i int = x var f float64 = x var b byte = x
有點類似薛丁格悖論,x 可以是一個 int、一個 float64,甚至是一個位元組,直到你分配它。這種暫時的靈活性讓 x 能夠順利地處理程式碼中的不同類型。無需強制轉換,保持整潔。
你甚至可以在表達式中混合不同類型的常數,Go 會找出結果的最佳類型:
const a = 1.5 const b = 2 const result = a * b // result is float64
由於a是浮點數,Go將整個表達式提升為float64。所以你不必擔心失去精確度——Go 可以處理它。但要小心:如果您嘗試將結果指派給 int,您將收到錯誤。 Go 不允許可能遺失資料的隱式轉換。
限制
這種靈活性只會走得很遠。將常數分配給變數後,變數的類型就會被設定:
const y = 10 var z int = y // z is an int var k float64 = y // y can still be used as float64
但是如果你嘗試這個:
const y = 10.5 var m int = y // Error: constant 10.5 truncated to integer
Go 會拋出錯誤,因為如果沒有明確強制轉換,它不會自動將浮點常數轉換為整數。因此,雖然常數很靈活,但它們不會更改類型以適應不相容的變數。
了解型別預設值
當您使用無類型常數而不指定類型時,它們會採用預設類型:
無型別整數常數 預設為 int。
無型浮點常數 預設為 float64。
無型別 Rune 常數 預設為 rune(int32)。
非型別複雜常數預設為complex128。
無型別字串常數預設為字串。
無型布林常數 預設為 bool。
這是一個快速表格:
Constant Kind | Can Adapt To |
---|---|
Untyped Integer | int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128 |
Untyped Float | float32, float64, complex64, complex128 |
Untyped Complex | complex64, complex128 |
Untyped Rune | rune, int32, any integer type that can hold the value |
Untyped String | string |
Untyped Boolean | bool |
Go 不僅在編譯時計算常數,它還最佳化常數表達式。這意味著你可以在計算中使用常數,Go 將在編譯期間計算結果:
const x = 10 var i int = x var f float64 = x var b byte = x
因此 c 不會在執行時重新計算; Go 在編譯時已經算出它是 520。這可以提高效能,尤其是在速度很重要的程式碼中。透過使用常數,Go 只處理一次計算,而不是每次程式運行時都進行計算。
Go 不像其他語言有預處理器,但您可以在 if 語句中使用常數在編譯時包含或排除程式碼。
const a = 1.5 const b = 2 const result = a * b // result is float64
當 debug 為 false 時,編譯器知道 if 條件永遠不會為 true,並且可能遺漏區塊內的程式碼。這可以使您的最終二進位檔案更小。非常方便,對吧?
Go 常數的一個強大功能是它們支援非常大的數字。 Go 中的無型別數值常數具有「無限」精度,僅受記憶體和編譯器的限制。
const y = 10 var z int = y // z is an int var k float64 = y // y can still be used as float64
儘管 bigNum 比 float64 或 int 等任何內建數位類型大得多,但 Go 允許您將其定義為常數。您可以在編譯時使用這些大數字進行計算:
const y = 10.5 var m int = y // Error: constant 10.5 truncated to integer
如果您一直在使用 Go,您可能已經看過用於建立枚舉常數的 iota。它很有用,因為它會自動分配增量值。
您也可以在常數宣告中使用 iota 的表達式來建立相關常數。
const a = 100 const b = 5 const c = a * b + 20 // c is computed at compile time
此程式碼使用位移位元定義千位元組、兆位元組、千兆位元組和太位元組的常數。它是在編譯時計算的。這是產生一系列相關常數的巧妙方法。
我發現 iota 對於這類事情非常有幫助。由於 Go 沒有內建枚舉類型,因此您可以使用 iota 識別碼和自訂類型有效地模擬枚舉。
常數可以使用位元運算和移位,甚至產生比任何內建類型都大的值。
const debug = false func main() { if debug { fmt.Println("Debugging enabled") } // The above block might be removed by the compiler if debug is false }
這裡,由於移位量很大,shiftedValue 變成非常大的數字。該值對於標準整數類型來說太大了,但在您嘗試分配它之前作為常數有效:
const bigNum = 1e1000 // This is a valid constant
這表示常數可以表示無法儲存在變數中的值,從而允許進行非常大的數字的編譯時計算。
雖然 Go 的常數很靈活,但有些事情他們無法做到。
常數不能被指標引用
常數在運行時沒有記憶體位址。所以你不能取得常數的位址或使用指向它的指標。
const x = 10 var i int = x var f float64 = x var b byte = x
帶型的常數 nil 指標
雖然 nil 可以指派給指標、切片、映射、通道和函數類型的變量,但您不能建立保存類型化 nil 指標的常數。
const a = 1.5 const b = 2 const result = a * b // result is float64
這增加了 Go 中常數的不變性和編譯時性質。
常數宣告中的函數呼叫
只有某些內建函數可以在常數表達式中使用,例如 len、cap、real、imag 和complex。
const y = 10 var z int = y // z is an int var k float64 = y // y can still be used as float64
這是因為,那些內建的函數都可以使用
複合型與常數
常數不能直接表示複合型,如切片、映射或結構。但你可以使用常數來初始化它們。
const y = 10.5 var m int = y // Error: constant 10.5 truncated to integer
上面的程式碼不起作用,因為你不能將切片聲明為常數。但是,您可以在變數切片內使用常數:
const a = 100 const b = 5 const c = a * b + 20 // c is computed at compile time
請記住,像 slice 這樣的型別本身不是常數 - 您不能將其宣告為常數。不過,裡面的元素可以是常數。
需要時明確轉換
如果由於類型不匹配或可能丟失精度而導致無類型常數無法直接賦值,則需要使用顯式類型轉換。
const debug = false func main() { if debug { fmt.Println("Debugging enabled") } // The above block might be removed by the compiler if debug is false }
我希望這能讓您對常數有更好的了解。它們不僅是簡單的固定值,而且是固定值。而且還有一個靈活的功能,可以讓您的程式碼更具表現力和效率。
我對分享 Go 經驗還比較陌生,我渴望學習和進步。如果您發現這篇文章有價值或對我如何改進它有建議,請在評論中發表。
我第一篇關於「Go 的 UTF-8 支援:一個有趣的限制」的 Reddit 貼文 (不需要登入) 引起了相當大的關注。
期待您的回饋。
以上是Go 的常數:超越基礎的詳細內容。更多資訊請關注PHP中文網其他相關文章!