fmt包實現了格式化I/O。主要分為向外輸出內容和獲取輸入內容兩大部分
一 向外輸出
標准庫fmt提供了以下幾種輸出相關函數。
1.1 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("lqz is NB")
name := "lqz"
fmt.Printf("我是:%s\n", name)
fmt.Println("打印並換行")
}
執行上面的代碼輸出:
lqz is NB我是:lqz
打印並換行
1.2 格式化輸出占位符
*printf系列函數都支持format格式化參數,在這里我們按照占位符將被替換的變量類型划分,方便查詢和記憶。
通用占位符
| 占位符 | 說明 |
|---|---|
| %v | 值的默認格式表示 |
| %+v | 類似%v,但輸出結構體時會添加字段名 |
| %#v | 值的Go語法表示 |
| %T | 打印值的類型 |
| %% | 百分號 |
示例代碼如下:
fmt.Printf("名字是:%v\n","lqz")
fmt.Printf("年齡是:%v\n",19)
p:= struct {
name string
age int
}{"lqz",19}
fmt.Printf("結構體內容為:%v\n",p)
fmt.Printf("結構體內容為(帶字段名):%+v\n",p) // 輸出結構體是會帶name
fmt.Printf("結構體內容為(值的Go語法表示):%#v\n",p) // 輸出結構體是會帶name
fmt.Printf("切片內容為:%v\n",[]int{4,5,6})
fmt.Printf("切片內容為(值的Go語法表示):%#v\n",[]int{4,5,6})
fmt.Printf("切片值的類型為:%T\n",[]int{4,5,6})
fmt.Printf("字符串值的類型為:%T\n","lqz")
fmt.Printf("打印百分百:100%%\n")
輸出結果如下:
名字是:lqz
年齡是:19
結構體內容為:{lqz 19}
結構體內容為(帶字段名):{name:lqz age:19}
結構體內容為(值的Go語法表示):struct { name string; age int }{name:"lqz", age:19}
切片內容為:[4 5 6]
切片內容為(值的Go語法表示):[]int{4, 5, 6}
切片值的類型為:[]int
字符串值的類型為:string
打印百分百:100%
布爾型
| 占位符 | 說明 |
|---|---|
| %t | true或false |
var limit bool = false;
fmt.Printf("limit=%t \n",limit)
整型
| 占位符 | 說明 |
|---|---|
| %b | 表示為二進制 |
| %c | 該值對應的unicode碼值 |
| %d | 表示為十進制 |
| %o | 表示為八進制 |
| %x | 表示為十六進制,使用a-f |
| %X | 表示為十六進制,使用A-F |
| %U | 表示為Unicode格式:U+1234,等價於”U+%04X” |
| %q | 該值對應的單引號括起來的go語法字符字面值,必要時會采用安全的轉義表示 |
示例代碼如下:
n := 3333
fmt.Printf("二進制表示:%b\n", n)
fmt.Printf("unicode對應的字符:%c\n", n)
fmt.Printf("十進制表示:%d\n", n)
fmt.Printf("八進制表示:%o\n", 9)
fmt.Printf("十六進制小寫:%x\n", 123)
fmt.Printf("十六進制大寫:%X\n", 123)
fmt.Printf("用引號引起來的字符字面值:%q\n", 65)
輸出結果如下:
二進制表示:110100000101
unicode對應的字符:അ
十進制表示:3333
八進制表示:11
十六進制小寫:7b
十六進制大寫:7B
用引號引起來的字符字面值:'A'
浮點數與復數
| 占位符 | 說明 |
|---|---|
| %b | 無小數部分、二進制指數的科學計數法,如-123456p-78 |
| %e | 科學計數法,如-1234.456e+78 |
| %E | 科學計數法,如-1234.456E+78 |
| %f | 有小數部分但無指數部分,如123.456 |
| %F | 等價於%f |
| %g | 根據實際情況采用%e或%f格式(以獲得更簡潔、准確的輸出) |
| %G | 根據實際情況采用%E或%F格式(以獲得更簡潔、准確的輸出) |
示例代碼如下:
f := 3.14159 fmt.Printf("無小數部分、二進制指數的科學計數法,(如-123456p-78):%b\n", f) fmt.Printf("科學計數法(-1234.456e+78):%e\n", f) fmt.Printf("科學計數法(如-1234.456E+78):%E\n", f) fmt.Printf("有小數部分但無指數部分:%f\n", f) fmt.Printf("有小數部分但無指數部分:%F\n", f) fmt.Printf("根據實際情況采用%%e或%%f格式(以獲得更簡潔、准確的輸出):%g\n", f) fmt.Printf("根據實際情況采用%%E或%%F格式(以獲得更簡潔、准確的輸出):%G\n", f)
輸出結果如下:
無小數部分、二進制指數的科學計數法,(如-123456p-78):7074231776675438p-51科學計數法(-1234.456e+78):3.141590e+00科學計數法(如-1234.456E+78):3.141590E+00有小數部分但無指數部分:3.141590有小數部分但無指數部分:3.141590根據實際情況采用%e或%f格式(以獲得更簡潔、准確的輸出):3.14159根據實際情況采用%E或%F格式(以獲得更簡潔、准確的輸出):3.14159
字符串和[]byte
| 占位符 | 說明 |
|---|---|
| %s | 直接輸出字符串或者[]byte |
| %q | 該值對應的雙引號括起來的go語法字符串字面值,必要時會采用安全的轉義表示 |
| %x | 每個字節用兩字符十六進制數表示(使用a-f) |
| %X | 每個字節用兩字符十六進制數表示(使用A-F) |
示例代碼如下:
name:="lqz" b:=[]byte{'l','q','z',65} fmt.Printf("字符串為:%s\n",name) fmt.Printf("切片為:%s\n",b) fmt.Printf("雙引號括起來的go語法字符串字面值:%q\n",name) fmt.Printf("雙引號括起來的go語法字符串字面值:%q\n",b) fmt.Printf("每個字節用兩字符十六進制數表示:%x\n",name) fmt.Printf("每個字節用兩字符十六進制數表示:%x\n",b) fmt.Printf("每個字節用兩字符十六進制數表示(使用a-f):%X\n",name) fmt.Printf("每個字節用兩字符十六進制數表示(使用A-F):%X\n",b)
輸出結果如下:
字符串為:lqz切片為:lqzA雙引號括起來的go語法字符串字面值:"lqz"雙引號括起來的go語法字符串字面值:"lqzA"每個字節用兩字符十六進制數表示:6c717a每個字節用兩字符十六進制數表示:6c717a41每個字節用兩字符十六進制數表示(使用a-f):6c717a每個字節用兩字符十六進制數表示(使用A-F):6C717A41
指針
| 占位符 | 說明 |
|---|---|
| %p | 表示為十六進制,並加上前導的0x |
示例代碼如下:
a := 99 fmt.Printf("%p\n", &a) fmt.Printf("%#p\n", &a)
輸出結果如下:
0xc000018078c000018078
寬度標識符
寬度通過一個緊跟在百分號后面的十進制數指定,如果未指定寬度,則表示值時除必需之外不作填充。精度通過(可選的)寬度后跟點號后跟的十進制數指定。如果未指定精度,會使用默認精度;如果點號后沒有跟數字,表示精度為0。舉例如下:
| 占位符 | 說明 |
|---|---|
| %f | 默認寬度,默認精度 |
| %9f | 寬度9,默認精度 |
| %.2f | 默認寬度,精度2 |
| %9.2f | 寬度9,精度2 |
| %9.f | 寬度9,精度0 |
示例代碼如下:
n := 12.34fmt.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.141593寬度9,默認精度: 3.141593默認寬度,精度2:3.14寬度9,精度2: 3.14寬度9,精度0: 3
其他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 := "劉清政" fmt.Printf("正常字符串輸出:%s\n", s) fmt.Printf("寬度是5,右對齊:%5s\n", s) fmt.Printf("寬度是5,左對齊:%-5s\n", s) fmt.Printf("總長度為3,截取2個,右對齊:%3.2s\n", s) fmt.Printf("總長度為3,截取2個,左對齊:%-3.2s\n", s) fmt.Printf("寬度為5,只要2個字符:%5.2s\n", s) fmt.Printf("寬度為5,不夠用0補齊:%05s\n", s)
輸出結果如下:
正常字符串輸出:劉清政寬度是5,右對齊: 劉清政寬度是5,左對齊:劉清政 總長度為3,截取2個,右對齊: 劉清總長度為3,截取2個,左對齊:劉清 寬度為5,只要2個字符: 劉清寬度為5,不夠用0補齊:00劉清政
1.3 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)
舉個例子:
func main() { // 向標准輸出寫入內容 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 := "lqz is nb" // 向打開的文件句柄中寫入內容 fmt.Fprintf(fileObj, "往文件中(標准輸出)寫如信息:%s", name)}
注意,只要滿足io.Writer接口的類型都支持寫入
1.4 Sprint
Sprint系列函數會把傳入的數據生成並返回一個字符串。
func Sprint(a ...interface{}) stringfunc Sprintf(format string, a ...interface{}) stringfunc Sprintln(a ...interface{}) string
簡單的示例代碼如下:
s1 := fmt.Sprint("lqz") name := "lqz" age := 18 s2 := fmt.Sprintf("姓名:%s,年齡:%d", name, age) s3 := fmt.Sprintln("lqz is nb") fmt.Println(s1, s2, s3)
lqz 姓名:lqz,年齡:18 lqz is nb
1.5 Errorf
Errorf函數根據format參數生成格式化字符串並返回一個包含該字符串的錯誤。
func Errorf(format string, a ...interface{}) error
通常使用這種方式來自定義錯誤類型,例如:
err := fmt.Errorf("這是一個錯誤")
Go1.13后版本為fmt.Errorf函數新加了一個%w占位符用來生成一個可以包裹Error的Wrapping Error。
e := errors.New("原始錯誤e")w := fmt.Errorf("Wrap了一個錯誤%w", e)
err := fmt.Errorf("這是一個錯誤") fmt.Printf("類型是:%T,值是:%v",err,err) fmt.Println("-----") e := errors.New("原始錯誤e") w := fmt.Errorf("Wrap了一個錯誤:%w", e) fmt.Println(w)
類型是:*errors.errorString,值是:這是一個錯誤-----Wrap了一個錯誤:原始錯誤e
二 獲取輸入
Go語言fmt包下有fmt.Scan、fmt.Scanf、fmt.Scanln三個函數,可以在程序運行過程中從標准輸入獲取用戶的輸入。
2.1 fmt.Scan
函數定簽名如下:
func Scan(a ...interface{}) (n int, err error)
- Scan從標准輸入掃描文本,讀取由空白符分隔的值保存到傳遞給本函數的參數中,換行符視為空白符。
- 本函數返回成功掃描的數據個數和遇到的任何錯誤。如果讀取的數據個數比提供的參數少,會返回一個錯誤報告原因。
具體代碼示例如下:
var ( name string age int ) fmt.Scan(&name, &age) fmt.Printf("輸入的值為: 姓名:%s 年齡:%d \n", name, age)
將上面的代碼編譯后在終端執行,在終端依次輸入小王子、28和false使用空格分隔。
lqz 19// 或者lqz19
fmt.Scan從標准輸入中掃描用戶輸入的數據,將以空白符分隔的數據分別存入指定的參數。
2.2 fmt.Scanf
函數簽名如下:
func Scanf(format string, a ...interface{}) (n int, err error)
- Scanf從標准輸入掃描文本,根據format參數指定的格式去讀取由空白符分隔的值保存到傳遞給本函數的參數中。
- 本函數返回成功掃描的數據個數和遇到的任何錯誤。
代碼示例如下:
var ( name string age int ) fmt.Scanf("name:%s age:%d", &name, &age) // 在控制台按照該格式輸入 fmt.Printf("掃描結果: 姓名:%s 年齡:%d \n", name, age)
將上面的代碼編譯后在終端執行,在終端按照指定的格式依次輸入小王子、28和false。
// 控制台按如下格式輸入name:lqz age:19掃描結果: 姓名:lqz 年齡:19
fmt.Scanf不同於fmt.Scan簡單的以空格作為輸入數據的分隔符,fmt.Scanf為輸入數據指定了具體的輸入內容格式,只有按照格式輸入數據才會被掃描並存入對應變量。
例如,我們還是按照上個示例中以空格分隔的方式輸入,fmt.Scanf就不能正確掃描到輸入的數據。
lqz 19掃描結果: 姓名: 年齡:0
2.3 fmt.Scanln
函數簽名如下:
func Scanln(a ...interface{}) (n int, err error)
- Scanln類似Scan,它在遇到換行時才停止掃描。最后一個數據后面必須有換行或者到達結束位置。
- 本函數返回成功掃描的數據個數和遇到的任何錯誤。
具體代碼示例如下:
var ( name string age int)fmt.Scanln(&name, &age)fmt.Printf("掃描結果 姓名:%s 年齡:%d \n", name, age)
將上面的代碼編譯后在終端執行,在終端依次輸入小王子、28和false使用空格分隔。
//輸入: 劉清政 19 敲回車掃描結果 姓名:劉清政 年齡:19
fmt.Scanln遇到回車就結束掃描了,這個比較常用。
2.4 bufio.NewReader
有時候我們想完整獲取輸入的內容,而輸入的內容可能包含空格,這種情況下可以使用bufio包來實現。示例代碼如下:
reader := bufio.NewReader(os.Stdin) // 從標准輸入生成讀對象fmt.Print("請輸入內容:")text, _ := reader.ReadString('\n') // 讀到換行text = strings.TrimSpace(text) // 去掉空白fmt.Printf("%#v\n", text)
請輸入內容:輸入的內容"輸入的內容"
2.5 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)
2.6 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)
var name string="lqz"
var newName string=""
fmt.Sscan(name,&newName) // 相當於把name的值賦值給newName
fmt.Println(name)
fmt.Println(newName)
