Go語言fmt.Printf使用指南
fmt標准庫是我們在學習Go語言過程中接觸最早最頻繁的一個了,本文介紹了fmtb包的一些常用函數。
fmt
fmt包實現了類似C語言printf和scanf的格式化I/O。主要分為向外輸出內容和獲取輸入內容兩大部分。
向外輸出
標准庫fmt
提供了以下幾種輸出相關函數。
Print
系列函數會將內容輸出到系統的標准輸出,區別在於Print
函數直接輸出內容,Printf
函數支持格式化輸出字符串,Println
函數會在輸出內容的結尾添加一個換行符。
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("在終端打印該信息。")
name := "沙河小王子"
fmt.Printf("我是:%s\n", name)
fmt.Println("在終端打印單獨一行顯示")
}
執行上面的代碼輸出:
在終端打印該信息。我是:沙河小王子
在終端打印單獨一行顯示
Fprint
Fprint
系列函數會將內容輸出到一個io.Writer
接口類型的變量w
中,我們通常用這個函數往文件中寫入內容。
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)
舉個例子:
// 向標准輸出寫入內容
fmt.Fprintln(os.Stdout, "向標准輸出寫入內容")
fileObj, err := os.OpenFile("./xx.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("打開文件出錯,err:", err)
return
}
name := "沙河小王子"
// 向打開的文件句柄中寫入內容
fmt.Fprintf(fileObj, "往文件中寫如信息:%s", name)
注意,只要滿足io.Writer
接口的類型都支持寫入。
Sprint
Sprint
系列函數會把傳入的數據生成並返回一個字符串。
func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
簡單的示例代碼如下:
s1 := fmt.Sprint("沙河小王子")
name := "沙河小王子"
age := 18
s2 := fmt.Sprintf("name:%s,age:%d", name, age)
s3 := fmt.Sprintln("沙河小王子")
fmt.Println(s1, s2, s3)
Errorf
Errorf
函數根據format參數生成格式化字符串並返回一個包含該字符串的錯誤。
func Errorf(format string, a ...interface{}) error
通常使用這種方式來自定義錯誤類型,例如:
err := fmt.Errorf("這是一個錯誤")
格式化占位符
*printf
系列函數都支持format格式化參數,在這里我們按照占位符將被替換的變量類型划分,方便查詢和記憶。
通用占位符
占位符 | 說明 |
---|---|
%v | 值的默認格式表示 |
%+v | 類似%v,但輸出結構體時會添加字段名 |
%#v | 值的Go語法表示 |
%T | 打印值的類型 |
%% | 百分號 |
示例代碼如下:
fmt.Printf("%v\n", 100)
fmt.Printf("%v\n", false)
o := struct{ name string }{"小王子"}
fmt.Printf("%v\n", o)
fmt.Printf("%#v\n", o)
fmt.Printf("%T\n", o)
fmt.Printf("100%%\n")
輸出結果如下:
100
false
{小王子}
struct { name string }{name:"小王子"}
struct { name string }
100%
布爾型
占位符 | 說明 |
---|---|
%t | true或false |
整型
占位符 | 說明 |
---|---|
%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)
輸出結果如下:
1000001
A
65
101
41
41
浮點數與復數
占位符 | 說明 |
---|---|
%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)
輸出結果如下:
6946802425218990p-49
1.234000e+01
1.234000E+01
12.340000
12.34
12.34
字符串和[]byte
占位符 | 說明 |
---|---|
%s | 直接輸出字符串或者[]byte |
%q | 該值對應的雙引號括起來的go語法字符串字面值,必要時會采用安全的轉義表示 |
%x | 每個字節用兩字符十六進制數表示(使用a-f |
%X | 每個字節用兩字符十六進制數表示(使用A-F) |
示例代碼如下:
s := "小王子"
fmt.Printf("%s\n", s)
fmt.Printf("%q\n", s)
fmt.Printf("%x\n", s)
fmt.Printf("%X\n", s)
輸出結果如下:
小王子
"小王子"
e5b08fe78e8be5ad90
E5B08FE78E8BE5AD90
指針
占位符 | 說明 |
---|---|
%p | 表示為十六進制,並加上前導的0x |
示例代碼如下:
a := 10
fmt.Printf("%p\n", &a)
fmt.Printf("%#p\n", &a)
輸出結果如下:
0xc000094000
c000094000
寬度標識符
寬度通過一個緊跟在百分號后面的十進制數指定,如果未指定寬度,則表示值時除必需之外不作填充。精度通過(可選的)寬度后跟點號后跟的十進制數指定。如果未指定精度,會使用默認精度;如果點號后沒有跟數字,表示精度為0。舉例如下:
占位符 | 說明 |
---|---|
%f | 默認寬度,默認精度 |
%9f | 寬度9,默認精度 |
%.2f | 默認寬度,精度2 |
%9.2f | 寬度9,精度2 |
%9.f | 寬度9,精度0 |
示例代碼如下:
n := 12.34
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)
輸出結果如下:
12.340000
12.340000
12.34
12.34
12
其他falg
占位符 | 說明 |
---|---|
’+’ | 總是輸出數值的正負號;對%q(%+q)會生成全部是ASCII字符的輸出(通過轉義); |
’ ‘ | 對數值,正數前加空格而負數前加負號;對字符串采用%x或%X時(% x或% X)會給各打印的字節之間加空格 |
’-’ | 在輸出右邊填充空白而不是默認的左邊(即從默認的右對齊切換為左對齊); |
’#’ | 八進制數前加0(%#o),十六進制數前加0x(%#x)或0X(%#X),指針去掉前面的0x(%#p)對%q(%#q),對%U(%#U)會輸出空格和單引號括起來的go字面值; |
‘0’ | 使用0而不是空格填充,對於數值類型會把填充的0放在正負號后面; |
舉個例子:
s := "小王子"
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)
輸出結果如下:
小王子
小王子
小王子
小王子
小王子
小王
00小王子
獲取輸入
Go語言fmt
包下有fmt.Scan
、fmt.Scanf
、fmt.Scanln
三個函數,可以在程序運行過程中從標准輸入獲取用戶的輸入。
fmt.Scan
函數定簽名如下:
func Scan(a ...interface{}) (n int, err error)
- Scan從標准輸入掃描文本,讀取由空白符分隔的值保存到傳遞給本函數的參數中,換行符視為空白符。
- 本函數返回成功掃描的數據個數和遇到的任何錯誤。如果讀取的數據個數比提供的參數少,會返回一個錯誤報告原因。
具體代碼示例如下:
func main() {
var (
name string
age int
married bool
)
fmt.Scan(&name, &age, &married)
fmt.Printf("掃描結果 name:%s age:%d married:%t \n", name, age, married)
}
將上面的代碼編譯后在終端執行,在終端依次輸入小王子
、28
和false
使用空格分隔。
$ ./scan_demo
小王子 28 false
掃描結果 name:小王子 age:28 married:false
fmt.Scan
從標准輸入中掃描用戶輸入的數據,將以空白符分隔的數據分別存入指定的參數。
fmt.Scanf
函數簽名如下:
func Scanf(format string, a ...interface{}) (n int, err error)
- Scanf從標准輸入掃描文本,根據format參數指定的格式去讀取由空白符分隔的值保存到傳遞給本函數的參數中。
- 本函數返回成功掃描的數據個數和遇到的任何錯誤。
代碼示例如下:
func main() {
var (
name string
age int
married bool
)
fmt.Scanf("1:%s 2:%d 3:%t", &name, &age, &married)
fmt.Printf("掃描結果 name:%s age:%d married:%t \n", name, age, married)
}
將上面的代碼編譯后在終端執行,在終端按照指定的格式依次輸入小王子
、28
和false
。
$ ./scan_demo
1:小王子 2:28 3:false
掃描結果 name:小王子 age:28 married:false
fmt.Scanf
不同於fmt.Scan
簡單的以空格作為輸入數據的分隔符,fmt.Scanf
為輸入數據指定了具體的輸入內容格式,只有按照格式輸入數據才會被掃描並存入對應變量。
例如,我們還是按照上個示例中以空格分隔的方式輸入,fmt.Scanf
就不能正確掃描到輸入的數據。
$ ./scan_demo
小王子 28 false
掃描結果 name: age:0 married:false
fmt.Scanln
函數簽名如下:
func Scanln(a ...interface{}) (n int, err error)
- Scanln類似Scan,它在遇到換行時才停止掃描。最后一個數據后面必須有換行或者到達結束位置。
- 本函數返回成功掃描的數據個數和遇到的任何錯誤。
具體代碼示例如下:
func main() {
var (
name string
age int
married bool
)
fmt.Scanln(&name, &age, &married)
fmt.Printf("掃描結果 name:%s age:%d married:%t \n", name, age, married)
}
將上面的代碼編譯后在終端執行,在終端依次輸入小王子
、28
和false
使用空格分隔。
$ ./scan_demo
小王子 28 false
掃描結果 name:小王子 age:28 married:false
fmt.Scanln
遇到回車就結束掃描了,這個比較常用。
bufio.NewReader
有時候我們想完整獲取輸入的內容,而輸入的內容可能包含空格,這種情況下可以使用bufio
包來實現。示例代碼如下:
func bufioDemo() {
reader := bufio.NewReader(os.Stdin) // 從標准輸入生成讀對象
fmt.Print("請輸入內容:")
text, _ := reader.ReadString('\n') // 讀到換行
text = strings.TrimSpace(text)
fmt.Printf("%#v\n", text)
}
Fscan系列
這幾個函數功能分別類似於fmt.Scan
、fmt.Scanf
、fmt.Scanln
三個函數,只不過它們不是從標准輸入中讀取數據而是從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)
Sscan系列
這幾個函數功能分別類似於fmt.Scan
、fmt.Scanf
、fmt.Scanln
三個函數,只不過它們不是從標准輸入中讀取數據而是從指定字符串中讀取數據。
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)