Golang 各種打印方法詳解
在 Golang 程序開發過程中,打印輸出是我們進行調試和日誌記錄的重要手段。Go 語言提供了豐富的打印函數,主要集中在 fmt
和 log
包中。本文將詳細介紹這些打印方法的使用場景、特點和示例代碼。
目錄
- fmt 包的打印函數
- log 包的打印函數
- 格式化動詞
- 自定義打印格式
- 實用技巧與最佳實踐
fmt 包的打印函數
fmt
包是 Go 語言中最常用的打印包,提供了多種打印函數,可以滿足不同場景的需求。
Print/Println/Printf
這三個函數是最基礎的打印函數,直接將內容輸出到標準輸出(通常是控制台)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package main
import "fmt"
func main() { fmt.Print("Hello", "World") fmt.Println("Hello", "World") name := "Gopher" age := 10 fmt.Printf("Name: %s, Age: %d\n", name, age) }
|
Sprint/Sprintln/Sprintf
這三個函數與上面的類似,但不是直接打印到控制台,而是返回格式化後的字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package main
import "fmt"
func main() { s1 := fmt.Sprint("Hello", "World") fmt.Println(s1) s2 := fmt.Sprintln("Hello", "World") fmt.Print(s2) name := "Gopher" age := 10 s3 := fmt.Sprintf("Name: %s, Age: %d", name, age) fmt.Println(s3) }
|
Fprint/Fprintln/Fprintf
這三個函數允許將內容打印到指定的 io.Writer
接口,例如文件、網絡連接等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package main
import ( "fmt" "os" )
func main() { file, err := os.Create("output.txt") if err != nil { fmt.Println("無法創建文件:", err) return } defer file.Close() fmt.Fprint(file, "Hello", "World") fmt.Fprintln(file, "Hello", "World") name := "Gopher" age := 10 fmt.Fprintf(file, "Name: %s, Age: %d\n", name, age) fmt.Println("內容已寫入到 output.txt 文件") }
|
log 包的打印函數
log
包提供了簡單的日誌功能,適合用於記錄程序運行過程中的信息、警告和錯誤。
log Print/Println/Printf
這些函數類似於 fmt
包中的對應函數,但會自動添加時間戳和前綴。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package main
import "log"
func main() { log.SetPrefix("[INFO] ") log.Print("系統啟動") log.Println("用戶登錄") user := "admin" log.Printf("用戶 %s 執行了操作", user) }
|
Fatal/Fatalln/Fatalf
這些函數在打印日誌後會調用 os.Exit(1)
終止程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package main
import "log"
func main() { err := "數據庫連接失敗" log.Println("這些函數會終止程序,所以在示例中被注釋掉") }
|
Panic/Panicln/Panicf
這些函數在打印日誌後會調用 panic()
,引發 panic。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main
import "log"
func main() { defer func() { if r := recover(); r != nil { log.Println("捕獲到 panic:", r) } }() err := "非法操作" log.Println("這些函數會引發 panic,所以在示例中被注釋掉") }
|
格式化動詞
在使用 Printf
、Sprintf
和 Fprintf
等格式化打印函數時,需要使用格式化動詞來指定如何格式化參數。以下是常用的格式化動詞:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package main
import "fmt"
func main() { fmt.Printf("%v\n", 123) fmt.Printf("%+v\n", struct{Name string}{"Gopher"}) fmt.Printf("%#v\n", []int{1, 2, 3}) fmt.Printf("%T\n", 3.14) fmt.Printf("%t\n", true) fmt.Printf("%d\n", 123) fmt.Printf("%b\n", 123) fmt.Printf("%o\n", 123) fmt.Printf("%x\n", 123) fmt.Printf("%X\n", 123) fmt.Printf("%f\n", 123.456) fmt.Printf("%.2f\n", 123.456) fmt.Printf("%e\n", 123.456) fmt.Printf("%E\n", 123.456) fmt.Printf("%s\n", "Hello") fmt.Printf("%q\n", "Hello") fmt.Printf("%c\n", 65) x := 123 fmt.Printf("%p\n", &x) fmt.Printf("|%6d|%6.2f|\n", 123, 123.456) fmt.Printf("|%-6d|%-6.2f|\n", 123, 123.456) }
|
自定義打印格式
Go 語言允許通過實現 fmt.Stringer
、fmt.GoStringer
、fmt.Formatter
等接口來自定義類型的打印格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package main
import ( "fmt" "strconv" )
type Person struct { Name string Age int }
func (p Person) String() string { return p.Name + ", " + strconv.Itoa(p.Age) + "歲" }
func (p Person) GoString() string { return "Person{Name: \"" + p.Name + "\", Age: " + strconv.Itoa(p.Age) + "}" }
func (p Person) Format(f fmt.State, c rune) { switch c { case 's': fmt.Fprint(f, p.String()) case 'v': if f.Flag('#') { fmt.Fprint(f, p.GoString()) } else { fmt.Fprint(f, p.String()) } case 'q': fmt.Fprintf(f, "\"%s\"", p.String()) } }
func main() { person := Person{Name: "張三", Age: 30} fmt.Printf("%s\n", person) fmt.Printf("%#v\n", person) fmt.Printf("%q\n", person) }
|
實用技巧與最佳實踐
1. 使用 log
包進行日誌記錄
在實際應用中,推薦使用 log
包或第三方日誌庫(如 logrus
、zap
等)進行日誌記錄,而不是直接使用 fmt.Print
系列函數。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package main
import ( "log" "os" )
func main() { logFile, err := os.Create("app.log") if err != nil { log.Fatal("無法創建日誌文件:", err) } defer logFile.Close() log.SetOutput(logFile) log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.SetPrefix("[APP] ") log.Println("應用程序啟動") log.Printf("配置加載完成,版本: %s", "1.0.0") log.Println("應用程序關閉") }
|
2. 使用 %+v
打印結構體
當需要調試複雜的結構體時,使用 %+v
格式化動詞可以同時顯示字段名和值,非常有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package main
import "fmt"
type Config struct { Host string Port int Debug bool Database struct { Name string User string Password string } }
func main() { config := Config{ Host: "localhost", Port: 8080, Debug: true, } config.Database.Name = "mydb" config.Database.User = "admin" config.Database.Password = "password123" fmt.Printf("%+v\n", config) }
|
3. 使用 %#v
生成可重用的代碼
在調試過程中,有時需要創建一個對象的副本。使用 %#v
可以生成 Go 語法表示,直接複製到代碼中使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package main
import "fmt"
func main() { data := map[string]interface{}{ "name": "張三", "age": 30, "roles": []string{"admin", "user"}, "active": true, } fmt.Printf("%#v\n", data) }
|
4. 使用 bytes.Buffer
高效拼接字符串
當需要拼接大量字符串時,使用 bytes.Buffer
比直接使用 +
運算符或 fmt.Sprintf
更高效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main
import ( "bytes" "fmt" )
func main() { var buffer bytes.Buffer buffer.WriteString("Hello") buffer.WriteString(", ") buffer.WriteString("World") buffer.WriteString("!") result := buffer.String() fmt.Println(result) buffer.Reset() fmt.Fprintf(&buffer, "Name: %s, Age: %d", "張三", 30) fmt.Println(buffer.String()) }
|
總結
Go 語言提供了豐富的打印函數,可以滿足不同場景的需求。在實際開發中,應根據具體情況選擇合適的打印方法:
- 調試時使用
fmt.Print
系列函數
- 日誌記錄使用
log
包或第三方日誌庫
- 字符串處理使用
fmt.Sprint
系列函數
- 文件輸出使用
fmt.Fprint
系列函數
掌握這些打印方法和格式化技巧,可以大大提高開發效率和代碼質量。