Go 常用標準庫之 fmt 介紹與基本使用
一、介紹
fmt 是 Go 語言中的一個常用標準庫,它用於格式化輸入和輸出資料。fmt 包提供了一系列函式,可以幫助你將資料以特定的格式列印到標準輸出(通常是終端)或將資料格式化為字串以供後續處理。這個庫的名稱 "fmt" 來自於 "format",因為它主要用於格式化資料。
fmt 包的主要功能包括:
- 格式化輸出:fmt 包提供了函式如
Print
,Printf
,Println
,Fprint
,Fprintf
, 和Fprintln
用於將資料輸出到標準輸出或指定的 io.Writer。你可以使用這些函式將資料以不同的格式列印到螢幕上或檔案中。 - 格式化輸入:fmt 包也支援從輸入源(通常是標準輸入)讀取資料,並根據格式規範解析資料。這是透過
Scan
,Scanf
, 和Scanln
函式實現的。這對於從使用者獲取輸入資料非常有用。 - 字串格式化:你可以使用
Sprintf
函式將資料格式化為字串而不是直接輸出到標準輸出,這對於構建日誌訊息或其他需要格式化的字串很有用。 - 錯誤格式化:fmt 包也提供了
Errorf
函式,用於將格式化的錯誤訊息作為 error 型別返回,方便錯誤處理。 - 格式化佔位符:在格式化字串中,你可以使用佔位符來指定如何格式化資料。常見的佔位符包括
%d
(整數),%f
(浮點數),%s
(字串)等。
二、向外輸出
標準庫 fmt
提供了多種用於輸出的函式,每個函式都有不同的用途和輸出方式。以下是一些常用的輸出相關函式:
2.1 Print 系列
Print
:用於將文字輸出到標準輸出。它接受任意數量的引數,並將它們串聯成一個字串輸出,不會新增換行符。Printf
:用於格式化輸出到標準輸出。它接受一個格式化字串和一系列引數,根據格式化字串的佔位符將引數格式化並輸出。Println
:類似於Print
,但會在輸出後自動新增一個換行符。
func Print(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
舉個簡單的例子:
func main() {
fmt.Print("Hello, ", "world")
name := "Alice"
age := 30
fmt.Printf("Hello, %s. You are %d years old.\n", name, age)
fmt.Println("Hello, world")
}
2.2 Fprint 系列
Fprint
系列函式用於將文字輸出到指定的 io.Writer
介面,而不僅僅是標準輸出。你可以將文字輸出到檔案、網路連線等。這些函式的引數列表包括一個 io.Writer
引數,以及任意數量的引數。
Fprint
:將文字輸出到指定的io.Writer
。Fprintf
:將格式化文字輸出到指定的io.Writer
。Fprintln
:將帶有換行符的文字輸出到指定的io.Writer
。
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
舉個例子:
func main() {
// 向標準輸出寫入內容
fmt.Fprintln(os.Stdout, "向標準輸出寫入內容")
fileObj, err := os.OpenFile("./output.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("開啟檔案出錯,err:", err)
return
}
name := "jarvis"
// 向開啟的檔案控制程式碼中寫入內容
fmt.Fprintf(fileObj, "往檔案中寫如資訊:%s", name)
}
這個示例建立了一個名為 "output.txt" 的檔案,並將資料寫入檔案中。
2.3 Sprint 系列
Sprint
系列函式用於將文字輸出到字串中,而不是標準輸出或檔案。它們將文字格式化為字串並返回結果。
Sprint
:將文字輸出到字串。Sprintf
:將格式化文字輸出到字串。Sprintln
:將帶有換行符的文字輸出到字串。
func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
簡單的示例程式碼如下:
func main() {
s1 := fmt.Sprint("jarvis")
name := "jarvis"
age := 18
s2 := fmt.Sprintf("name:%s,age:%d", name, age)
s3 := fmt.Sprintln("jarvis")
fmt.Println(s1, s2, s3)
}
2.4 Errorf 系列
Errorf
系列函式用於建立格式化的錯誤訊息並返回一個 error
型別的值。這允許你將格式化的錯誤訊息返回給呼叫者,以便更好地進行錯誤處理。這些函式的用法類似於 Sprintf
,但它們返回一個 error
值而不是字串。
Errorf
:根據format
引數生成格式化字串並返回一個包含該字串的錯誤。
func Errorf(format string, a ...interface{}) error
通常使用這種方式來自定義錯誤型別,例如:
err := fmt.Errorf("這是一個錯誤")
三、格式化佔位符
*printf
系列函式都支援format格式化引數,在這裡我們按照佔位符將被替換的變數型別劃分,方便查詢和記憶。
3.1 通用佔位符
通用佔位符用於格式化不同型別的資料:
佔位符 | 說明 |
---|---|
%v | 值的預設格式表示 |
%+v | 類似%v,但輸出結構體時會新增欄位名 |
%#v | 值的Go語法表示 |
%T | 列印值的型別 |
%% | 百分號 |
程式碼示例:
func main() {
fmt.Printf("%v\n", 100)
fmt.Printf("%v\n", false)
o := struct{ name string }{"jarvis"}
fmt.Printf("%v\n", o)
fmt.Printf("%#v\n", o)
fmt.Printf("%T\n", o)
fmt.Printf("100%%\n")
}
3.2 布林型
佔位符 | 說明 |
---|---|
%t | true或false |
3.3 整型
佔位符 | 說明 |
---|---|
%b | 表示為二進位制 |
%c | 該值對應的unicode碼值 |
%d | 表示為十進位制 |
%o | 表示為八進位制 |
%x | 表示為十六進位制,使用a-f |
%X | 表示為十六進位制,使用A-F |
%U | 表示為Unicode格式:U+1234,等價於"U+%04X" |
%q | 該值對應的單引號括起來的go語法字元字面值,必要時會採用安全的轉義表示 |
示例程式碼如下:
n := 65
fmt.Printf("%b\n", n)
fmt.Printf("%c\n", n)
fmt.Printf("%d\n", n)
fmt.Printf("%o\n", n)
fmt.Printf("%x\n", n)
fmt.Printf("%X\n", n)
3.4 浮點數與複數
佔位符 | 說明 |
---|---|
%b | 無小數部分、二進位制指數的科學計數法,如-123456p-78 |
%e | 科學計數法,如-1234.456e+78 |
%E | 科學計數法,如-1234.456E+78 |
%f | 有小數部分但無指數部分,如123.456 |
%F | 等價於%f |
%g | 根據實際情況採用%e或%f格式(以獲得更簡潔、準確的輸出) |
%G | 根據實際情況採用%E或%F格式(以獲得更簡潔、準確的輸出) |
示例程式碼如下:
f := 12.34
fmt.Printf("%b\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%E\n", f)
fmt.Printf("%f\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%G\n", f)
3.5 字串和[]byte
佔位符 | 說明 |
---|---|
%s | 直接輸出字串或者[]byte |
%q | 該值對應的雙引號括起來的go語法字串字面值,必要時會採用安全的轉義表示 |
%x | 每個位元組用兩字元十六進位制數表示(使用a-f |
%X | 每個位元組用兩字元十六進位制數表示(使用A-F) |
示例程式碼如下:
s := "jarvis"
fmt.Printf("%s\n", s)
fmt.Printf("%q\n", s)
fmt.Printf("%x\n", s)
fmt.Printf("%X\n", s)
3.6 指標
佔位符 | 說明 |
---|---|
%p | 表示為十六進位制,並加上前導的0x |
示例程式碼如下:
a := 18
fmt.Printf("%p\n", &a)
fmt.Printf("%#p\n", &a)
3.7 寬度識別符號
寬度透過一個緊跟在百分號後面的十進位制數指定,如果未指定寬度,則表示值時除必需之外不作填充。精度透過(可選的)寬度後跟點號後跟的十進位制數指定。如果未指定精度,會使用預設精度;如果點號後沒有跟數字,表示精度為0。舉例如下
佔位符 | 說明 |
---|---|
%f | 預設寬度,預設精度 |
%9f | 寬度9,預設精度 |
%.2f | 預設寬度,精度2 |
%9.2f | 寬度9,精度2 |
%9.f | 寬度9,精度0 |
示例程式碼如下:
n := 88.88
fmt.Printf("%f\n", n)
fmt.Printf("%9f\n", n)
fmt.Printf("%.2f\n", n)
fmt.Printf("%9.2f\n", n)
fmt.Printf("%9.f\n", n)
3.8 其他flag
佔位符 | 說明 |
---|---|
‘+’ | 總是輸出數值的正負號;對%q(%+q)會生成全部是ASCII字元的輸出(透過轉義); |
’ ' | 對數值,正數前加空格而負數前加負號;對字串採用%x或%X時(% x或% X)會給各列印的位元組之間加空格 |
‘-’ | 在輸出右邊填充空白而不是預設的左邊(即從預設的右對齊切換為左對齊); |
‘#’ | 八進位制數前加0(%#o),十六進位制數前加0x(%#x)或0X(%#X),指標去掉前面的0x(%#p)對%q(%#q),對%U(%#U)會輸出空格和單引號括起來的go字面值; |
‘0’ | 使用0而不是空格填充,對於數值型別會把填充的0放在正負號後面; |
舉個例子:
s := "jarvis"
fmt.Printf("%s\n", s)
fmt.Printf("%5s\n", s)
fmt.Printf("%-5s\n", s)
fmt.Printf("%5.7s\n", s)
fmt.Printf("%-5.7s\n", s)
fmt.Printf("%5.2s\n", s)
fmt.Printf("%05s\n", s)
四、獲取輸入
Go 語言的 fmt
包提供了 fmt.Scan
、fmt.Scanf
和 fmt.Scanln
這三個函式,用於從標準輸入獲取使用者的輸入。這些函式允許你與使用者互動,從標準輸入流中讀取不同型別的資料並將其儲存在相應的變數中。
4.1 fmt.Scan 函式
Scan
函式用於從標準輸入中獲取使用者的輸入,並將輸入的資料儲存在變數中。它根據空格分隔輸入,適合獲取多個輸入值。
函式定義如下:
func Scan(a ...interface{}) (n int, err error)
- Scan從標準輸入掃描文字,讀取由空白符分隔的值儲存到傳遞給本函式的引數中,換行符視為空白符。
- 本函式返回成功掃描的資料個數和遇到的任何錯誤。如果讀取的資料個數比提供的引數少,會返回一個錯誤報告原因。
具體程式碼示例如下:
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Enter your name: ")
fmt.Scan(&name)
fmt.Print("Enter your age: ")
fmt.Scan(&age)
fmt.Printf("Name: %s, Age: %d\n", name, age)
}
在這個示例中,fmt.Scanf
使用格式字串 %s %d
來解析輸入的姓名和年齡。
4.2 fmt.Scanln 函式
Scanln
函式用於從標準輸入中獲取使用者的輸入,並將輸入的資料儲存在變數中,每行一個變數。它通常用於獲取多個輸入值,每個值在單獨的行中輸入。
函式定義如下:
func Scanln(a ...interface{}) (n int, err error)
- Scanln類似Scan,它在遇到換行時才停止掃描。最後一個資料後面必須有換行或者到達結束位置。
- 本函式返回成功掃描的資料個數和遇到的任何錯誤。
程式碼示例:
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Enter your name: ")
fmt.Scanln(&name)
fmt.Print("Enter your age: ")
fmt.Scanln(&age)
fmt.Printf("Name: %s, Age: %d\n", name, age)
}
在上面的示例中,fmt.Scanln
用於獲取使用者輸入的姓名和年齡,並將它們儲存在相應的變數中。輸入的每一行都對應一個變數。
4.3 fmt.Scanf 函式
Scanf
函式用於根據格式規範解析輸入,並將資料儲存在變數中。它允許你指定輸入的格式,並可以處理不同型別的資料。
函式簽名如下:
func Scanf(format string, a ...interface{}) (n int, err error)
- Scanf從標準輸入掃描文字,根據format引數指定的格式去讀取由空白符分隔的值儲存到傳遞給本函式的引數中。
- 本函式返回成功掃描的資料個數和遇到的任何錯誤。
程式碼示例如下:
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Enter your name and age: ")
fmt.Scanf("%s %d", &name, &age)
fmt.Printf("Name: %s, Age: %d\n", name, age)
}
在這個示例中,fmt.Scanf
使用格式字串 %s %d
來解析輸入的姓名和年齡。
4.4 使用 bufio
包獲取輸入
bufio
包提供了一種更靈活的方式來處理輸入,特別是在需要完整讀取一行或多行輸入的情況下。你可以使用 bufio.NewReader
建立一個輸入緩衝區,然後使用 ReadString
函式來讀取輸入,直到指定的分隔符(例如換行符 \n
)。這允許你獲取包含空格在內的完整輸入內容。
func bufioDemo() {
reader := bufio.NewReader(os.Stdin) // 從標準輸入生成讀物件
fmt.Print("請輸入內容:")
text, _ := reader.ReadString('\n') // 讀取直到換行符
text = strings.TrimSpace(text)
fmt.Printf("%#v\n", text)
}
4.5 使用 Fscan
系列函式
Fscan
系列函式允許你從 io.Reader
介面中讀取資料,而不僅僅是標準輸入。這些函式與 fmt.Scan
、fmt.Scanf
和 fmt.Scanln
類似,但允許你從任何實現 io.Reader
介面的地方讀取資料。
Fscan
:從io.Reader
中讀取資料。Fscanln
:從io.Reader
中讀取一行資料。Fscanf
:根據指定的格式從io.Reader
中讀取資料。
func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
程式碼示例:
package main
import (
"fmt"
"strings"
)
func main() {
input := "42 John"
reader := strings.NewReader(input) // 從字串生成讀物件
var age int
var name string
n, err := fmt.Fscanf(reader, "%d %s", &age, &name)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Read %d values: Age: %d, Name: %s\n", n, age, name)
}
4.6 使用 Sscan
系列函式
Sscan
系列函式允許你從字串中讀取資料,而不僅僅是從標準輸入。這些函式與 fmt.Scan
、fmt.Scanf
和 fmt.Scanln
類似,但允許你從字串中讀取資料。
Sscan
:從字串中讀取資料。Sscanln
:從字串中讀取一行資料。Sscanf
:根據指定的格式從字串中讀取資料。
func Sscan(str string, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
程式碼示例:
package main
import (
"fmt"
)
func main() {
input := "Alice 30"
var name string
var age int
n, err := fmt.Sscanf(input, "%s %d", &name, &age)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Read %d values: Name: %s, Age: %d\n", n, name, age)
}