本文 AI 產出,尚未審核
Golang – 基本語法與資料型態
主題:格式化輸出(fmt.Printf, fmt.Sprintf)
簡介
在日常開發中,將資料以易讀的方式輸出是每個程式設計師必備的技巧。Go 語言提供的 fmt 套件,不僅能夠簡單地列印字串,還支援豐富的格式化功能,讓開發者可以精確控制輸出的外觀、寬度、對齊方式以及數值的進位制等。
掌握 fmt.Printf 與 fmt.Sprintf 的用法,能讓你在除錯、日誌記錄、報表產生或是 CLI 工具的使用者介面上,寫出既美觀又易於維護的輸出。本篇文章將從概念說明、實作範例、常見陷阱到最佳實踐,全面介紹 Go 的格式化輸出。
核心概念
1. fmt 套件的兩大函式
| 函式 | 作用 | 主要回傳值 |
|---|---|---|
fmt.Printf(format, a…) |
直接把格式化結果寫入標準輸出 (stdout) |
無(回傳寫入的位元組數) |
fmt.Sprintf(format, a…) |
產生格式化字串並回傳 | 格式化後的 string |
重點:
Printf用於即時顯示;Sprintf用於組合字串後再做其他處理(例如寫入檔案、傳遞給 API)。
2. 格式化動詞(Verb)
Go 使用 百分號 (%) 開頭的動詞來指定資料的顯示方式,常見的有:
| 動詞 | 說明 | 範例 |
|---|---|---|
%v |
預設格式(結構體會列出欄位) | fmt.Printf("%v", p) |
%+v |
同 %v,但會顯示結構體欄位名稱 |
fmt.Printf("%+v", p) |
%#v |
Go 語法表示的值(可直接用於 go run) |
fmt.Printf("%#v", p) |
%T |
顯示資料的型別 | fmt.Printf("%T", x) |
%d |
十進位整數 | fmt.Printf("%d", 42) |
%b |
二進位 | fmt.Printf("%b", 5) |
%x / %X |
十六進位(小寫/大寫) | fmt.Printf("%x", 255) |
%f |
浮點數(預設 6 位小數) | fmt.Printf("%f", 3.14159) |
%e / %E |
科學記號(小寫/大寫) | fmt.Printf("%e", 1.23e4) |
%s |
字串 | fmt.Printf("%s", "hello") |
%q |
帶雙引號的字串(可直接作為 Go 原始字面值) | fmt.Printf("%q", "go") |
%t |
布林值 (true/false) |
fmt.Printf("%t", true) |
%p |
指標位址(十六進位) | fmt.Printf("%p", &x) |
3. 旗標(Flag)與寬度、精度
| 旗標 | 功能 |
|---|---|
- |
左對齊(預設右對齊) |
+ |
顯示正負號(對於數值) |
(空格) |
正數前加空格,負數前保留負號 |
# |
依據動詞的不同,添加前綴(如 0x、0) |
0 |
前置零填充(寬度不足時) |
寬度:在動詞前寫入一個整數,指定最小欄位寬度。
精度:在寬度之後加上 . 再寫入整數,對於浮點數表示小數位數,對於字串則限制最大長度。
fmt.Printf("%8d", 42) // " 42"
fmt.Printf("%-8d", 42) // "42 "
fmt.Printf("%08d", 42) // "00000042"
fmt.Printf("%.2f", 3.14159) // "3.14"
fmt.Printf("%6.2f", 3.14159) // " 3.14"
程式碼範例
以下示範 5 個常見且實用的格式化情境,均附有說明註解。
範例 1:列印結構體與欄位名稱
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
p := Person{Name: "Alice", Age: 30}
// %v 只顯示值
fmt.Printf("預設: %v\n", p) // {Alice 30}
// %+v 顯示欄位名稱
fmt.Printf("欄位名稱: %+v\n", p) // {Name:Alice Age:30}
// %#v 產生可直接編譯的 Go 語法
fmt.Printf("Go 語法: %#v\n", p) // main.Person{Name:"Alice", Age:30}
}
範例 2:對齊與填充 – 報表排版
package main
import "fmt"
func main() {
fmt.Println("商品\t價格\t庫存")
fmt.Printf("%-10s %8.2f %6d\n", "蘋果", 12.5, 120) // 左對齊商品名
fmt.Printf("%-10s %08.2f %6d\n", "香蕉", 8.3, 45) // 前置零填充價格
}
輸出
商品 價格 庫存
蘋果 12.50 120
香蕉 08.30 45
範例 3:十六進位與二進位顯示 – 位元操作除錯
package main
import "fmt"
func main() {
var flags uint8 = 0b10101010 // 170
fmt.Printf("十進位: %d\n", flags)
fmt.Printf("十六進位: %#x\n", flags) // 加上 0x 前綴
fmt.Printf("二進位: %08b\n", flags) // 8 位、前置零
}
範例 4:使用 Sprintf 組合字串 – 日誌與錯誤訊息
package main
import (
"fmt"
"log"
"os"
)
func main() {
filename := "data.txt"
line := 42
msg := fmt.Sprintf("檔案 %s 第 %d 行發生錯誤", filename, line)
// 寫入日誌檔
logger := log.New(os.Stdout, "ERROR: ", log.LstdFlags)
logger.Println(msg)
}
範例 5:自訂格式化 – Stringer 介面
package main
import (
"fmt"
)
// 自訂類別實作 fmt.Stringer
type Point struct {
X, Y float64
}
// String 方法會在 %v、%s 等動詞被呼叫時自動使用
func (p Point) String() string {
return fmt.Sprintf("(%.2f, %.2f)", p.X, p.Y)
}
func main() {
pt := Point{X: 3.1415, Y: 2.7182}
fmt.Printf("座標: %v\n", pt) // 會呼叫 Point.String()
}
常見陷阱與最佳實踐
| 陷阱 | 說明 | 建議的解決方式 |
|---|---|---|
忘記加 \n |
Printf 不會自動換行,容易導致輸出黏在一起。 |
使用 fmt.Println 或在格式字串最後手動加 \n。 |
| 寬度與精度寫反 | fmt.Printf("%2.4f", x) 會被解讀為「最小寬度 2、精度 4」,若寬度太小會被忽略。 |
先確定「寬度 > 精度」再寫,或直接使用 fmt.Sprintf("%6.2f", x)。 |
%v 與 %+v 混用 |
在大型結構體中直接使用 %v 可能看不到欄位名稱,除錯時不易辨識。 |
除錯時使用 %+v,正式輸出時根據需求選擇。 |
指標與 %p |
%p 只接受指標類型,傳入非指標會編譯錯誤。 |
確認變數為指標或使用 fmt.Sprintf("%#v", &v) 取得位址資訊。 |
過度使用 Sprintf |
大量 Sprintf 會產生不必要的字串分配,影響效能。 |
若僅需直接輸出,使用 Printf;若需組合字串,才使用 Sprintf。 |
最佳實踐:
- 統一風格:在專案中約定使用的動詞與寬度(例如表格輸出全部使用
%-12s、%8d),減少維護成本。 - 使用
log套件:結合Printf的格式化能力與log的時間戳、等級標記,提升日誌可讀性。 - 避免硬編碼:若格式化需求會變動,將寬度、精度抽成變數或常數,方便未來調整。
- 測試輸出:對於需要精確排版的功能(如 CLI 表格),寫單元測試比對產生的字串,確保格式不會因 Go 版本變更而破壞。
實際應用場景
CLI 工具
- 使用
Printf產生對齊的表格、選單或進度條。 - 例:
go run ./cmd/mytool --list列出資源時,透過% -15s %8d排版,使使用者一眼看出欄位意義。
- 使用
日誌與監控
- 結合
log.New與Sprintf,在錯誤訊息中加入變數值、時間戳與呼叫堆疊。 - 例:
log.Printf("user=%s action=%s duration=%dms", uid, act, ms)。
- 結合
報表產出
- 產生 CSV、Markdown 或 HTML 表格時,先用
Sprintf組合每一列字串,再寫入檔案。 - 例:
row := fmt.Sprintf("%s,%d,%.2f", name, qty, price)。
- 產生 CSV、Markdown 或 HTML 表格時,先用
除錯與測試
- 在單元測試失敗時,用
%#v輸出結構體的完整 Go 語法,方便直接貼回程式碼作為測試案例。
- 在單元測試失敗時,用
總結
fmt.Printf 與 fmt.Sprintf 是 Go 語言中最常使用的格式化工具。透過熟悉各種動詞、旗標、寬度與精度的組合,你可以:
- 快速產出美觀的 CLI 輸出
- 撰寫結構化且易於除錯的日誌
- 在程式內部彈性組合字串(如報表、錯誤訊息)
本文從概念說明、實作範例、常見陷阱到最佳實踐,提供了完整的學習路徑。建議讀者在日常開發中刻意練習這些格式化技巧,並將團隊的格式化風格寫入程式碼規範,長期下來會大幅提升程式碼可讀性與維護效率。祝你在 Golang 的旅程中,寫出既清晰又專業的輸出!