如何在 Go 中使用變量和常量
變量 是一個需要掌握的重要編程概念。它們是代表你在程序中使用的值的符號。
本教程將介紹一些變量基礎知識和在你創建的 Go 程序中使用它們的最佳實踐。
理解變量
用術語來說,變量將存儲位置分配給與符號名稱或標識符相關的值。我們使用變量名來引用計算機程序中存儲的值。
我們可以將變量視爲帶有名稱的標籤,您可以將其綁定到值上。
假設我們有一個整數 1032049348
,我們希望將它存儲在一個變量中,而不是一遍又一遍地不斷地重新輸入長數字。爲了達到這個目的,我們可以使用一個容易記住的名字,比如變量 i
。要將值存儲在變量中,我們使用以下語法:
i := 1032049348
我們可以把這個變量想象成一個與值綁定的標籤。
標籤上寫有變量名 i
,並與整數值 1032049348
相關聯。
i := 1032049348
是一個聲明和賦值語句,由幾個部分組成:
-
變量名 (
i
) -
變量聲明賦值 (
:=
) -
與變量名綁定的值(
1032049348
) -
Go 推斷的數據類型 (
int
)
稍後我們將在下一節中看到如何顯式設置類型。
這些部分共同構成了將變量 i
設置爲整數 1032049348
的值的語句。
一旦我們設置一個等於某個值的變量,變量就會被_初始化_或創建出來。一旦我們這樣做了,我們就可以使用變量而不是值了。
一旦我們將 i
設置爲 1032049348
,我們可以使用 i
代替整數,所以讓我們打印出來:
package main
import "fmt"
func main() {
i := 1032049348
fmt.Println(i)
}
Output
1032049348
我們還可以通過使用變量快速輕鬆地進行數學運算。使用i := 1032049348
,我們可以使用以下語法減去整數值813
:
fmt.Println(i - 813)
Output
1032048535
在這個例子中,Go 爲我們做數學運算,從變量 i 中減去 813 以返回總和 1032048535。
說到數學,變量可以設置爲某個數學方程的結果。你還可以將兩個數字相加並將總和的值存儲到變量 x
中:
x := 76 + 145
你可能已經注意到這個例子看起來和代數很像。就像我們在公式和方程式中使用字母和其他符號來表示數字和數量一樣,變量是表示數據類型值的符號名稱。對於正確的 Go 語法,你需要確保你的變量位於任何等式的左側。
讓我們繼續打印 x
:
package main
import "fmt"
func main() {
x := 76 + 145
fmt.Println(x)
}
Output
221
Go 返回值 221
因爲變量 x
被設置爲等於 76
和 145
的總和。
變量可以表示任何數據類型,而不僅僅是整數:
s := "Hello, World!"
f := 45.06
b := 5 > 9 // A Boolean value will return either true or false
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}
如果你打印這些變量中的任何一個,Go 將返回該變量等價的內容。讓我們使用 slice
數據類型的賦值語句:
package main
import "fmt"
func main() {
slice := []string{"one", "two", "three"}
fmt.Println(slice)
}
Output
[one two three]
我們將 []string{"one", "two", "three"}
的切片值分配給變量 slice
,然後使用 fmt.Println
函數通過調用 slice
打印出該值。
變量通過在你的計算機中開闢一小塊內存區域來工作,該區域接受指定的值,然後與該空間相關聯。
聲明變量
在 Go 中,有多種聲明變量的方法,在某些情況下,聲明完全相同的變量和值的方法不止一種。
我們可以在不初始化的情況下聲明一個數據類型爲 int
的名爲 i
的變量。這意味着我們將聲明一個空間來放置一個值,但不給它一個初始值:
var i int
這將創建一個數據類型爲 int
的 i
的變量。
我們可以使用等於 (=
) 運算符來初始化值,如下例所示:
var i int = 1
在 Go 中,這兩種聲明形式都稱爲_長變量聲明_。
我們也可以使用_短變量聲明_:
i := 1
在這種情況下,我們有一個名爲 i
的變量和一個 int
數據類型。當我們不指定數據類型時,Go 會推斷數據類型。
對於聲明變量的三種方式,Go 社區採用了以下習慣用法:
-
僅在不初始化變量時使用長格式,
var i int
。 -
在聲明和初始化時使用縮寫形式,
i := 1
。 -
如果你不希望 Go 推斷數據類型,但仍想使用短變量聲明,則可以使用以下語法將值包裝爲所需類型:
i := int64(1)
當我們初始化值時,長變量聲明形式在 Go 中是不常用的:
var i int = 1
遵循 Go 社區關於如何聲明變量的方式,以便其他人可以無縫閱讀你的程序。
零值
所有內置類型的默認值都爲零值。任何分配的變量都是可用的,即使它從未分配過值。我們可以看到以下類型的零值:
package main
import "fmt"
func main() {
var a int
var b string
var c float64
var d bool
fmt.Printf("var a %T = %+v\n", a, a)
fmt.Printf("var b %T = %q\n", b, b)
fmt.Printf("var c %T = %+v\n", c, c)
fmt.Printf("var d %T = %+v\n\n", d, d)
}
Output
var a int = 0
var b string = ""
var c float64 = 0
var d bool = false
我們在 fmt.Printf
語句中使用了 %T
。這告訴函數打印變量的 數據類型
。
在 Go 中,因爲所有值都有一個 零
值,所以我們不能像其他一些語言那樣有 “未定義” 值。例如,某些語言中的 boolean
可能是 undefined
、true
或 false
,它允許變量有三種
狀態。在 Go 中,一個布爾值的狀態不能超過 兩個
。
命名變量:規則和樣式
變量的命名相當靈活,但有一些規則需要牢記:
-
變量名只能是一個單詞(如沒有空格)。
-
變量名稱必須僅由字母、數字和下劃線 (
_
) 組成。 -
變量名不能以數字開頭。
按照這些規則,讓我們看看有效和無效的變量名:
此外,在命名變量時請記住它們區分大小寫。這些名稱 userName
、USERNAME
、UserName
和 uSERNAME
都是完全不同的變量。最好避免在程序中使用相似的變量名稱,以確保你和你的合作者(當前和未來)都能保持變量的正確性。
雖然變量區分大小寫,但變量首字母的大小寫在 Go 中具有特殊含義。如果變量以大寫字母開頭,則該變量可以在聲明它的包(或 exporter
)之外訪問。如果變量以小寫字母開頭,則它僅在聲明它的包中可用。
var Email string
var password string
Email
以大寫字母開頭,可以被其他包訪問。password
以小寫字母開頭,只能在聲明它的包內訪問。
在 Go 中使用非常簡潔(或短)的變量名是很常見的。變量 userName
和 user
之間的選擇,通常會選擇 user
。
作用域在變量名稱的簡潔性方面也發揮了作用。規則是變量存在的作用域越小,變量名越小:
names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
fmt.Printf("index: %d = %q\n", i, n)
}
我們在更大的作用域內使用變量 names
,因此通常給它一個更有意義的名稱以幫助記住它在程序中的含義。但是,我們在下一行代碼中立即使用 i
和 n
變量,然後不再使用它們…… 因此,它不會讓閱讀代碼的人混淆變量的使用位置,或者它們代表的意思。
接下來,讓我們介紹一些關於變量樣式的注意事項。使用 MixedCaps
或 mixedCaps
而不是下劃線作爲多詞名稱。
風格最重要的是要保持一致,並且你所在的團隊同意這種風格。
重新分配變量
正如 變量
一詞所暗示的那樣,我們可以輕鬆地更改 Go 變量。這意味着我們可以通過重新分配將不同的值與先前分配的變量聯繫起來。能夠重新分配變量是很有用的,因爲在整個程序過程中,我們可能需要將用戶生成的值賦給已經初始化的變量中。我們可能還需要將分配更改爲先前定義的內容。
在處理其他人編寫的大型程序時,知道變量可以被重新分配對我們是很有幫助的,特別是當我們不清楚哪些變量已經被定義了。
讓我們將 76
的值分配給一個名爲 i
的類型爲 int
的變量,然後爲它分配一個新的值 42
:
package main
import "fmt"
func main() {
i := 76
fmt.Println(i)
i = 42
fmt.Println(i)
}
Output
76
42
這個例子表明我們可以先給變量 i
賦值一個整數,然後再重新賦值變量 i
,這次賦值爲 42
。
注意:當你聲明和初始化一個變量時,你可以使用:=
,但是,當你想簡單地改變一個已經聲明的變量的值時,你只需要使用等號運算符 (=
)。
因爲 Go 是一種靜態強類型語言,我們不能將一種類型分配給另一種類型。例如,我們不能將值 "Sammy"
分配給 int
類型的變量:
i := 72
i = "Sammy"
嘗試相互分配不同的類型將導致編譯時錯誤:
Output
cannot use "Sammy" (type string) as type int in assignment
Go 不允許我們多次聲明相同變量名:
var s string
var s string
Output
s redeclared in this block
如果我們嘗試對同一個變量名多次使用短變量聲明,我們也會收到編譯錯誤。這可能會發生錯誤,因此瞭解錯誤消息的含義是有幫助的:
i := 5
i := 10
Output
no new variables on left side of :=
與變量聲明類似,考慮變量的命名將提高你和其他人在將來維護程序的可讀性。
多重賦值
Go 還允許我們爲同一行中的多個變量分配多個值。這些值中的每一個都可以是不同的數據類型:
j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
Output
shark
2.05
15
在這個例子中,變量 j
被賦值給字符串 shark
,變量 k
被賦值給浮點數 2.05
,變量 l
被賦值給整數 15
。
這種在一行中將多個變量分配給多個值的方法可以減少代碼中的行數。但是,重要的是不要因爲更少的代碼行而損害可讀性。
全局和局部變量
在程序中使用變量時,牢記_變量作用域_很重要。變量的作用域是指可以從給定程序的代碼中訪問的特定位置。也就是說,並非所有變量都可以從給定程序的所有部分訪問——有些變量是全局變量,有些變量是局部變量。
全局變量存在於函數之外。局部變量存在於函數中。
讓我們看一下全局和局部變量的作用:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
}
func main() {
printLocal()
fmt.Println(g)
}
Output
local
global
這裏我們使用 var g = "global"
在函數外部創建一個全局變量。然後我們定義函數printLocal()
。在函數內部,分配了一個名爲 l
的局部變量,然後打印出來。程序先調用 printLocal()
,然後打印全局變量 g
。
因爲 g
是一個全局變量,我們可以在 printLocal()
中引用它。讓我們修改之前的程序來做到這一點:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
fmt.Println(g)
}
func main() {
printLocal()
fmt.Println(g)
}
Output
local
global
global
我們首先聲明一個全局變量 g
,var g = "global"
。在 main
函數中,我們調用函數printLocal
,它聲明瞭一個局部變量l
並打印出來,fmt.Println(l)
。然後,printLocal
打印出全局變量g
,fmt.Println(g)
。即使 g
沒有在 printLocal
中定義,它仍然可以被訪問,因爲它是在全局作用域內聲明的。最後,main
函數也打印出 g
。
現在讓我們嘗試在函數外部調用局部變量:
package main
import "fmt"
var g = "global"
func printLocal() {
l := "local"
fmt.Println(l)
}
func main() {
fmt.Println(l)
}
Output
undefined: l
我們不能在分配它的函數之外使用局部變量。如果你嘗試這樣做,編譯時會收到 未定義
錯誤。
讓我們看另一個例子,我們對全局變量和局部變量使用相同的變量名:
package main
import "fmt"
var num1 = 5
func printNumbers() {
num1 := 10
num2 := 7
fmt.Println(num1)
fmt.Println(num2)
}
func main() {
printNumbers()
fmt.Println(num1)
}
Output
10
7
5
在這個程序中,我們兩次聲明瞭 num1
變量。首先,我們在全局作用域內聲明瞭num1
,var num1 = 5
,然後再次在 printNumbers
函數的本地作用域內聲明 num1 := 10
。當我們從 main
程序中打印 num1
時,我們看到 5
的值被打印出來了。這是因爲 main
只看到全局變量聲明。但是,當我們從 printNumbers
函數中打印出 num1
時,它會看到本地聲明,並會打印出 10
的值。儘管 printNumbers
創建了一個名爲 num1
的新變量併爲其分配了 10
的值,但它不會影響值爲 5
的 num1
的全局實例。
使用變量時,你還需要考慮程序的哪些部分需要訪問每個變量;相應地採用全局或局部變量。在 Go 程序中,你會發現局部變量通常更常見。
常量
常量就像變量一樣,除了它們一旦被聲明就不能被修改。常量對於定義在程序中多次使用但不能更改的值很有用。
例如,如果我們想聲明購物車系統的稅率,我們可以使用一個常數,然後在程序的不同區域計算稅收。在未來的某個時候,如果稅率發生變化,我們只需在程序中的一個位置更改該值。如果我們使用了一個變量,我們可能會在程序中不小心更改某個值,從而導致計算不正確。
要聲明一個常量,我們可以使用以下語法:
const shark = "Sammy"
fmt.Println(shark)
Output
Sammy
如果我們在聲明後嘗試修改常量,我們會得到一個編譯時錯誤:
Output
cannot assign to shark
常量可以是 untyped
。這在處理整數類型數據等數字時很有用。如果常量是 untyped
,它會被顯式轉換,而 typed
常量則不是。讓我們看看如何使用常量:
package main
import "fmt"
const (
year = 365
leapYear = int32(366)
)
func main() {
hours := 24
minutes := int32(60)
fmt.Println(hours * year)
fmt.Println(minutes * year)
fmt.Println(minutes * leapYear)
}
Output
8760
21900
21960
如果你用一個類型聲明一個常量,它將是那個確切的類型。在這裏,當我們聲明常量 leapYear
時,我們將其定義爲數據類型 int32
。因此它是一個 typed
常量,這意味着它只能對 int32
數據類型進行操作。我們聲明的 year
常量沒有類型,所以它被認爲是 untyped
。因此,你可以將它與任何整數數據類型一起使用。
當hours
被定義時,它_推斷_它是int
類型,因爲我們沒有明確地給它一個類型,hours := 24
。當我們聲明 minutes
時,我們明確地將其聲明爲 int32
,minutes := int32(60)
。
現在讓我們來看看每個計算以及它的工作原理:
hours * year
在這種情況下,hours
是 int
,而 years
是 untyped。當程序編譯時,它顯式地將 years
轉換爲 int
,這使得乘法運算成功。
minutes * year
在這種情況下,minutes
是 int32
,而 year
是 untyped。當程序編譯時,它顯式地將 years
轉換爲 int32
,從而允許乘法運算成功。
minutes * leapYear
在這種情況下,minutes
是 int32
,而 leapYear
是 int32
的 typed 常量。這次編譯器無需執行任何操作,因爲這兩個變量已經屬於同一類型。
如果我們嘗試將兩種類型不兼容的類型相乘,程序將無法編譯:
fmt.Println(hours * leapYear)
Output
invalid operation: hours * leapYear (mismatched types int and int32)
在這種情況下,hours
被推斷爲 int
,而 leapYear
被顯式聲明爲 int32
。因爲 Go 是一種強類型語言,所以 int
和 int32
不兼容數學運算。要將它們相乘,你需要 將其中一個轉換爲int32
或int
。
結論
在本教程中,我們回顧了 Go 中變量的一些常見用例。變量是編程的重要組成部分,充當我們在程序中使用的數據類型的值的代表。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/jV981928S6-xMx485CvoeQ