本文 AI 產出,尚未審核
Golang 基本語法與資料型態
單元:變數宣告與初始化(var、:=)
簡介
在任何程式語言中,變數都是最基礎也是最重要的概念之一。它負責在程式執行期間暫存資料,讓我們可以重複使用、計算或傳遞資訊。對於 Go(Golang)而言,變數的宣告與初始化更具備靜態型別檢查與自動推斷的雙重優勢,使程式碼既安全又簡潔。
本篇文章將深入探討 Go 中兩種最常使用的變數寫法——var 關鍵字與短宣告運算子 :=。透過實作範例、常見陷阱與最佳實踐,讓讀者從「不知道怎麼宣告」一步步成長為「能在實務專案中自信使用」的開發者。
核心概念
1. var 宣告的完整語法
var 是 Go 官方提供的變數宣告方式,語法如下:
var <變數名稱> <型別> = <初始值>
- 型別必須寫明,除非使用 零值(zero value)初始化。
- 若省略
= <初始值>,變數會自動取得該型別的零值(例如int為0、string為""、bool為false)。
範例 1:基本型別宣告與零值
package main
import "fmt"
func main() {
var i int // i 的零值是 0
var s string // s 的零值是空字串 ""
var b bool // b 的零值是 false
fmt.Printf("i=%d, s=%q, b=%t\n", i, s, b)
}
重點:使用
var時,若不提供初始值,Go 會自動以零值填充,避免未初始化的記憶體讀取問題。
2. 型別推斷與多變數同時宣告
Go 允許在同一行宣告多個變數,只要型別相同或使用型別推斷即可。
var a, b, c int = 1, 2, 3 // 明確指定型別
var x, y = 3.14, "hello" // 依照右側值自動推斷型別
範例 2:多變數同時宣告
package main
import "fmt"
func main() {
var width, height int = 800, 600
var pi, greeting = 3.14159, "Go 語言"
fmt.Println("畫面尺寸:", width, "x", height)
fmt.Println("π =", pi, "訊息:", greeting)
}
3. 短宣告運算子 :=
在函式內部(區塊作用域)最常使用 :=,語法為:
<變數名稱> := <初始值>
- 不需要寫型別,編譯器會根據右側表達式自動推斷。
- 必須同時 宣告 且 初始化,不能僅宣告而不給值。
- 若已有同名變數在外層作用域,
:=會重新宣告(shadow)該變數,除非在同一行同時使用已存在的變數。
範例 3:函式內的短宣告
package main
import "fmt"
func main() {
// 使用 := 直接宣告並初始化
counter := 0
message := "開始計數"
fmt.Println(message, counter)
// 重新宣告(遮蔽)外層變數
counter := 10 // 這裡的 counter 與上面的不同
fmt.Println("重新宣告後的 counter =", counter)
}
注意:
:=只能在函式內部使用,若在全域範圍(package level)使用會產生編譯錯誤。
4. 結合 var 與 := 的實務寫法
在大型專案中,常見的寫法是:
- 全域變數:使用
var(可加上const、iota等)以明確型別與註解。 - 局部變數:盡可能使用
:=,讓程式碼更簡潔且型別安全。
範例 4:全域與局部變數混合
package main
import "fmt"
// 全域變數,使用 var 明確宣告
var (
AppName string = "MyGoApp"
Version int = 1
)
func main() {
// 局部變數,使用短宣告
startTime := "2025-12-19 10:00:00"
fmt.Printf("%s v%d 啟動於 %s\n", AppName, Version, startTime)
// 需要重新宣告同名變數時,使用 var 明確
var startTime = "2025-12-19 10:01:00" // 重新宣告,遮蔽上層 startTime
fmt.Println("重新宣告後的 startTime =", startTime)
}
5. 常見型別與零值對照表
| 型別 | 零值 (Zero Value) |
|---|---|
int |
0 |
float64 |
0.0 |
string |
"" (空字串) |
bool |
false |
pointer |
nil |
slice |
nil (長度 0) |
map |
nil |
channel |
nil |
interface |
nil |
了解零值可以避免因未初始化而產生的nil panic。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
在全域使用 := |
:= 只能在函式內部使用,放在檔案最上層會編譯失敗。 |
使用 var 或 const 於全域宣告。 |
| 遮蔽(shadow)變數 | 同名變數在內層作用域被 := 重新宣告,可能導致意外的值被使用。 |
盡量避免在同一區塊內同名變數,或使用 var 明確重新賦值。 |
| 忘記初始化 | var x int 只會得到零值,若預期是其他值會產生邏輯錯誤。 |
若需要非零初始值,務必在宣告時賦值或使用 :=。 |
多變數同時使用 := 時的型別不一致 |
a, b := 1, "two" 會推斷 a 為 int、b 為 string,若後續想把 b 改為 int 會出錯。 |
確認每個變數的型別需求,必要時使用 var 明確指定。 |
使用 var 但忘記 = |
var x int 5 會編譯錯誤。 |
正確語法是 var x int = 5 或 var x = 5(型別推斷)。 |
最佳實踐
- 全域變數:使用
var(或const)並加上說明性註解。 - 局部變數:優先使用
:=,讓編譯器自動推斷型別。 - 避免遮蔽:在同一函式內,若需要重新賦值,直接使用
=而非:=。 - 保持一致的宣告風格:團隊可以制定「變數宣告規範」,例如「所有函式入口參數使用明確型別」等。
- 善用 IDE /
go vet:這些工具會提醒未使用的變數、遮蔽問題與零值使用情形。
實際應用場景
1. 設定檔與環境變數
在微服務或 CLI 應用中,常需要讀取環境變數並轉型。使用 var 配合 os.Getenv 可以清楚表達「此變數可能為空」的意圖。
package main
import (
"fmt"
"os"
"strconv"
)
var (
// 這裡使用 var,因為它是全域設定
Port int
)
func init() {
// 讀取環境變數,若未設定則使用預設值 8080
pStr := os.Getenv("APP_PORT")
if pStr == "" {
Port = 8080
} else {
if p, err := strconv.Atoi(pStr); err == nil {
Port = p
} else {
fmt.Println("APP_PORT 不是有效的數字,使用預設 8080")
Port = 8080
}
}
}
func main() {
fmt.Printf("伺服器將在 %d 埠口啟動\n", Port)
}
2. 迴圈內的計數器
在 for 迴圈中,使用短宣告 := 可以讓計數器的生命週期僅限於迴圈內,避免意外泄漏。
package main
import "fmt"
func main() {
numbers := []int{5, 10, 15}
for i, n := range numbers {
// i, n 只在此迴圈作用域內有效
fmt.Printf("第 %d 個元素 = %d\n", i, n)
}
// 這裡若嘗試使用 i、n 會編譯錯誤
}
3. 立即函式(IIFE)與資源釋放
在需要快速建立暫時變數、執行完畢即釋放的情境(例如測試、一次性計算),可以結合 := 與匿名函式。
package main
import "fmt"
func main() {
// 立即執行函式,裡面的變數只在此作用域內
result := func() int {
tmp := 42 // 只在此匿名函式內部
return tmp * 2
}()
fmt.Println("計算結果 =", result)
}
總結
var與:=是 Go 中最核心的兩種變數宣告方式,各有適用範圍。var:適合全域、需要明確型別或零值初始化的情境。:=:在函式內部快速宣告、型別推斷、保持程式碼簡潔的最佳選擇。- 熟悉零值、遮蔽與多變數同時宣告的細節,可避免常見的 runtime 錯誤。
- 在實務開發中,結合最佳實踐(避免遮蔽、明確註解、使用工具檢查)能讓程式碼更安全、易讀、易維護。
掌握了變數的正確宣告與初始化,你就能在 Go 專案中自信地管理資料、撰寫乾淨的程式碼,為後續的函式、結構體、介面等更高階概念奠定堅實基礎。祝你在 Go 的旅程中一路順風! 🚀