golang:常量
定義
在 Go 語言中,術語”常量”用於表示固定的值。比如5
、-89
、I love Go
、67.89
等等。
看看下面的程式碼:
var a int = 50 var b string = "I love Go"
在上面的程式碼中,常量a
和b
分別被賦值為常量50
和I love GO
。關鍵字const
被用於表示常量,比如50
和I love Go
。即使在上面的程式碼中我們沒有明確的使用關鍵字const
,但是在 Go 的內部,它們是常量。
顧名思義,常量不能再重新賦值為其他的值。因此下面的程式將不能正常工作,它將出現一個編譯錯誤:cannot assign to a.
。
package main func main() {const a = 55 // 允許 a = 89 // 不允許重新賦值 }
常量的值會在編譯的時候確定。因為函式呼叫發生在執行時,所以不能將函式的返回值賦值給常量。
package main import ( "fmt" "math" ) func main() { fmt.Println("Hello, playground") var a = math.Sqrt(4) // 允許 const b = math.Sqrt(4) // 不允許 }
在上面的程式中,因為a
是變數,因此我們可以將函式math.Sqrt(4)
的返回值賦值給它(我們將在單獨的地方詳細討論函式)。
b
是一個常量,它的值需要在編譯的時候就確定。函式math.Sqrt(4)
只會在執行的時候計算,因此const b = math.Sqrt(4)
將會丟擲錯誤error main.go:11: const initializer math.Sqrt(4) is not a constant)
字串常量
雙引號中的任何值都是 Go 中的字串常量。例如像Hello World
或Sam
等字串在 Go 中都是常量。
什麼型別的字串屬於常量?答案是無型別的。
像Hello World
這樣的字串常量沒有任何型別。
const hello = "Hello World"
上面的例子,我們把Hello World
hello
。現在常量hello
有型別嗎?答案是沒有。常量仍然沒有型別。
Go 是一門強型別語言,所有的變數必須有明確的型別。那麼, 下面的程式是如何將無型別的常量Sam
賦值給變數name
的呢?
package main import ( "fmt" ) func main() { var name = "Sam" fmt.Printf("type %T value %v", name, name) }
答案是無型別的常量有一個與它們相關聯的預設型別,並且當且僅當一行程式碼需要時才提供它。在宣告中var name = "Sam"
,name
需要一個型別,它從字串常量Sam
的預設型別中獲取。
有沒有辦法建立一個帶型別的常量?答案是可以的。以下程式碼建立一個有型別常量。
const typedhello string = "Hello World"
上面程式碼中,typedhello
就是一個string
型別的常量。
Go 是一個強型別的語言,在分配過程中混合型別是不允許的。讓我們通過以下程式看看這句話是什麼意思。
package main func main() { var defaultName = "Sam" // 允許 type myString string var customName myString = "Sam" // 允許 customName = defaultName // 不允許 }
在上面的程式碼中,我們首先建立一個變數defaultName
並分配一個常量Sam
。常量Sam
的預設型別是string
,所以在賦值後defaultName
是string
型別的。
下一行,我們將建立一個新型別myString
,它是string
的別名。
然後我們建立一個myString
的變數customName
並且給他賦值一個常量Sam
。因為常量Sam
是無型別的,它可以分配給任何字串變數。因此這個賦值是允許的,customName
的型別是myString
。
現在,我們有一個型別為string
的變數defaultName
和另一個型別為myString
的變數customName
。即使我們知道這個myString
是string
型別的別名。Go 的型別策略不允許將一種型別的變數賦值給另一種型別的變數。因此將defaultName
賦值給customName
是不允許的,編譯器會丟擲一個錯誤main.go:7:20: cannot use defaultName (type string) as type myString in assignmen
。
布林常量
布林常量和字串常量沒有什麼不同。他們是兩個無型別的常量true
和false
。字串常量的規則適用於布林常量,所以在這裡我們不再重複。以下是解釋布林常量的簡單程式。
package main func main() { const trueConst = true type myBool bool var defaultBool = trueConst // 允許 var customBool myBool = trueConst // 允許 defaultBool = customBool // 不允許 }
上面的程式是自我解釋的。
數字常量
數字常量包含整數、浮點數和複數的常量。數字常量中有一些微妙之處。
讓我們看一些例子來說清楚。
package main import ( "fmt" ) func main() { const a = 5 var intVar int = a var int32Var int32 = a var float64Var float64 = a var complex64Var complex64 = a fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var) }
上面的程式,常量a
是沒有型別的,它的值是5
。您可能想知道a
的預設型別是什麼,如果它確實有一個的話, 那麼我們如何將它分配給不同型別的變數。答案在於a
的語法。下面的程式將使事情更加清晰。
package main import ( "fmt" ) func main() { var i = 5 var f = 5.6 var c = 5 + 6i fmt.Printf("i's type %T, f's type %T, c's type %T", i, f, c) }
在上面的程式中,每個變數的型別由數字常量的語法決定。5
在語法中是整數,5.6
是浮點數,5+6i
的語法是複數。當我們執行上面的程式,它會打印出i's type int, f's type float64, c's type complex128
。
現在我希望下面的程式能夠正確的工作。
package main import ( "fmt" ) func main() { const a = 5 var intVar int = a var int32Var int32 = a var float64Var float64 = a var complex64Var complex64 = a fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var) }
在這個程式中,a
的值是5
,a
的語法是通用的(它可以代表一個浮點數、整數甚至是一個沒有虛部的複數),因此可以將其分配給任何相容的型別。這些常量的預設型別可以被認為是根據上下文在執行中生成的。var intVar int = a
要求a
是int
,所以它變成一個int
常量。var complex64Var complex64 = a
要求a
是complex64
,因此它變成一個複數型別。很簡單的:)。
數字表達式
數字常量可以在表示式中自由混合和匹配,只有當它們被分配給變數或者在需要型別的程式碼中的任何地方使用時,才需要型別。
package main import ( "fmt" ) func main() { var a = 5.9/8 fmt.Printf("a's type %T value %v",a, a) }
在上面的程式中,5.9
在語法中是浮點型,8
是整型,5.9/8
是允許的,因為兩個都是數字常量。除法的結果是0.7375
是一個浮點型,所以a
的型別是浮點型。這個程式的輸出結果是:a's type float64 value 0.7375
。