這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
[TOC]
說明
fmt 包實現了格式化 I/O 函數,類似於 C 的 printf 和 scanf
格式“預留位置”衍生自 C,但比 C 更簡單
常用格式化輸出
fmt.Printf("start at number %v, end count %v\n",start, count)
注意參數輸出數量和預留位置數量要一致
IDEA開發快速格式化模板
使用IDEA開發可以配置自訂代碼模板快速產生
Settings -> Editor -> Live Templates
選中 go 語言展開 選則增加一條
- Abbreviation 填寫 fpf
- Description 填寫 print fmt format
- Template text
fmt.Printf("$END$",$VAR$)
- Applicable in 點擊右側
Define選中 Go: statenebt
Paste_Image.png
使用時在Go語言編輯的函數中輸入 fpf 就會自動開始編寫格式化輸出
Paste_Image.png
同理可以配置
fpfl 自動模板,協助填寫一個格式化後自動換行,內容
fmt.Printf("$END$\n",$VAR$)
喜歡log的輸出也可以自己定義模板
預留位置
一般預留位置
| 符號 |
說明 |
| %v |
相應值的預設格式 |
| %+v |
在列印結構體時,預設格式,會添加欄位名 |
| %#v |
相應值的 Go 文法表示 |
| %T |
相應值的類型的 Go 文法表示 |
| %% |
字面上的百分比符號,並非值的預留位置 |
布爾預留位置
整數預留位置
| 符號 |
說明 |
| %b |
二進位表示 |
| %c |
相應 Unicode 碼點所表示的字元 |
| %d |
十進位表示 |
| %o |
八進位表示 |
| %q |
單引號圍繞的字元字面值,由 Go 文法安全地轉義 |
| %x |
十六進位表示,字母形式為小寫 a-f |
| %X |
十六進位表示,字母形式為大寫 A-F |
| %U |
Unicode 格式:U+1234,等同於 "U+%04X" |
浮點數及其複合構成預留位置
| 符號 |
說明 |
| %b |
無小數部分的,指數為二的冪的科學計數法,與 strconv.FormatFloat 的 'b' 轉換格式一致。例如 -123456p-78 |
| %e |
科學計數法,例如 -1234.456e+78 |
| %E |
科學計數法,例如 -1234.456E+78 |
| %f |
有小數點而無指數,例如 123.456 |
| %g |
根據情況選擇 %e 或 %f 以產生更緊湊的(無末尾的 0)輸出 |
| %G |
根據情況選擇 %E 或 %f 以產生更緊湊的(無末尾的 0)輸出 |
字串與位元組切片預留位置
| 符號 |
說明 |
| %s |
字串或切片的無解譯位元組 |
| %q |
雙引號圍繞的字串,由 Go 文法安全地轉義 |
| %x |
十六進位,小寫字母,每位元組兩個字元 |
| %X |
十六進位,大寫字母,每位元組兩個字元 |
指標
這裡沒有 'u' 標記。若整數為無符號類型,他們就會被列印成無符號的
類似地, 這裡也不需要指定運算元的大小(int8,int64)。
寬度與精度的控制格式以 Unicode 碼點為單位。(這點與 C 的 printf 不同, 它以位元組數為單位。)
二者或其中之一均可用字元 '*' 表示, 此時它們的值會從下一個運算元中擷取,該運算元的類型必須為 int。
// 寬度與精度的控制以 Unicode 碼點為單位fmt.Printf("\"%8s\"\n", "123456") // 最大長度為 8// " 123456"fmt.Printf("\"%8s\"\n", "Hello") // 最大長度為 8// " Hello"// 寬度與精度均可用字元 '*' 表示fmt.Printf("%0*.*f \n", 8, 3, 13.25) // 總長度 8,小數位元 3fmt.Printf("%08.3f \n", 13.25) // 總長度 8,小數位元 3// 0013.250
對數值而言,寬度為該數值佔用地區的最小寬度;精度為小數點之後的位元
但對於 %g/%G 而言,精度為所有數位總數。
例如,對於 123.45,格式 %6.2f 會列印 123.45,而 %.4g 會列印 123.5。
%e 和 %f 的預設精度為 6;但對於 %g 而言,它的預設精度為確定該值所必須的最小位元
- 對大多數值而言,寬度為輸出的最小字元數,如果必要的話會為已格式化的形式填充空格。
- 對字串而言,精度為輸出的最大字元數,如果必要的話會直接截斷。
// 寬度與精度標記字串fmt.Printf("%8q", "ABC") // 最小長度為 8(包括 %q 的引號字元)// "ABC"fmt.Printf("%.8q", "1234567890") // 最大長度為 8(不包括 %q 的引號字元)// "12345678"
其它標記
| 符號 |
說明 |
| + |
總列印數值的加號或減號;對於 %q(%+q)保證只輸出 ASCII 編碼的字元 |
| - |
在右側而非左側填充空格(靠左對齊該地區) |
| # |
備用格式:對八進位添加前置 0(%#o),對十六進位添加前置 0x(%#x)或 0X(%#X)對 %p(%#p)去掉前置 0x |
- 如果可能的話,%q(%#q)會列印原始(即反引號圍繞的)字串
- 如果是可列印字元,%U(%#U)會寫出該字元的 Unicode 編碼形式(如字元 x 會被列印成 U+0078 'x')
' ' (空格)為數值中省略的加號或減號留出空白(% d);以十六進位(% x, % X)列印字串或切片時,在位元組之間用空格隔開
fmt.Printf("% x\n", "Hello")// 48 65 6c 6c 6f
0 填充前置的 0 而非空格;對於數字,這會將填充移到加號或減號之後
標記有時會被預留位置忽略,所以不要指望它們。例如十進位沒有備用格式,因此 %#d 與 %d 的行為相同
對於每一個 Printf 類的函數,都有一個 Print 函數,該函數不接受任何格式化, 它等價於對每一個運算元都應用 %v
另一個變參函數 Println 會在運算元之間插入空白, 並在末尾追加一個分行符號
不考慮預留位置的話,如果運算元是介面值,就會使用其內部的具體值,而非介面本身
因此:
var i interface{} = 23fmt.Printf("%v\n", i)// 會列印 23
- 若一個運算元實現了 Formatter 介面,該介面就能更好地用於控制格式化。
- 若其格式(它對於 Println 等函數是隱式的 %v)對於字串是有效(%s %q %v %x %X),以下兩條規則也適用:
- 若一個運算元實現了 error 介面,Error 方法就能將該對象轉換為字串,隨後會根據預留位置的需要進行格式化。
- 若一個運算元實現了 String() string 方法,該方法能將該對象轉換為字串,隨後會根據預留位置的需要進行格式化。
// 為避免以下這類遞迴的情況type X stringfunc (x X) String() string { return Sprintf("<%s>", x) }// 需要在遞迴前轉換該值func (x X) String() string { return Sprintf("<%s>", string(x)) }
格式化錯誤輸出
如果給預留位置提供了無效的實參(例如將一個字串提供給 %d),所產生的字串會包含該問題的描述,如下例所示:
// 類型錯誤或預留位置未知:%!verb(type=value)Printf("%d", hi)// %!d(string=hi)// 實參太多:%!(EXTRA type=value)Printf("hi", "guys")// hi%!(EXTRA string=guys)// 實參太少:%!verb(MISSING)Printf("hi%d")// hi %!d(MISSING)// 寬度或精度不是 int 類型:%!(BADWIDTH)或 %!(BADPREC)Printf("%*s", 4.5, "hi")// %!(BADWIDTH)hiPrintf("%.*s", 4.5, "hi")// %!(BADPREC)hi
所有錯誤都始於“%!”,有時緊跟著單個字元(預留位置),並以小括弧括住的描述結尾
掃描
一組類似的函數通過掃描已格式化的文本來產生值
| 函數 |
說明 |
| Scan、Scanf 和 Scanln |
從 os.Stdin 中讀取 |
| Fscan、Fscanf 和 Fscanln |
從指定的 io.Reader 中讀取 |
| Sscan、Sscanf 和 Sscanln |
從實參字串中讀取 |
| Scanln、Fscanln 和 Sscanln |
在分行符號處停止掃描,且需要條目緊隨分行符號之後 |
| Scanf、Fscanf 和 Sscanf |
需要輸入分行符號來匹配格式中的分行符號;其它函數則將分行符號視為空白格 |
| Scanf、Fscanf 和 Sscanf |
根據格式字串解析實參,類似於 Printf |
例如,%x 會將一個整數掃描為十六進位數,而 %v 則會掃描該值的預設表現格式
格式化行為類似於 Printf,但也有如下例外:
寬度被解釋為輸入的文本(%5s 意為最多從輸入中讀取 5 個符文來掃描成字串),而掃描函數則沒有精度的文法(沒有 %5.2f,只有 %5f)
當以某種格式進行掃描時,無論在格式中還是在輸入中,所有非空的連續空白字元 (除分行符號外)都等價於單個空格
- 由於這種限制,格式字串文本必須匹配輸入的文本,如果不匹配,掃描過程就會停止,並返回已掃描的實參數
- 在所有的掃描參數中,若一個運算元實現了 Scan 方法(即它實現了 Scanner 介面),該運算元將使用該方法掃描其文本
此外,若已掃描的實參數少於所提供的實參數,就會返回一個錯誤
所有需要被掃描的實參都必須是基本類型或實現了 Scanner 介面的類型
Fscan 等函數會從輸入中多讀取一個字元(符文),因此,如果迴圈調用掃描函數,可能會跳過輸入中的某些資料
一般只有在輸入的資料中沒有空白符時該問題才會出現。
- 若提供給 Fscan 的讀取器實現了 ReadRune,就會用該方法讀取字元
- 若此讀取器還實現了 UnreadRune 方法,就會用該方法儲存字元,而連續的調用將不會遺失資料
- 若要為沒有 ReadRune 和 UnreadRune 方法的讀取器加上這些功能,需使用 bufio.NewReader