golang格式化輸出-fmt包用法詳解


注意:我在這里給出golang查詢關於包的使用的地址:https://godoc.org 

   

聲明:

  此片文章並非原創,大多數內容都是來自:https://godoc.org/fmt,通過谷歌翻譯進行翻譯而來。

 

 

import "fmt"

  fmt包實現了類似C語言printf和scanf的格式化I/O。格式化verb('verb')源自C語言但更簡單。

Printing

verb:

通用:

1 %v    值的默認格式表示。當輸出結構體時,擴展標志(%+v)會添加字段名
2 %#v    值的Go語法表示
3 %T    值的類型的Go語法表示
4 %%    百分號

  案例展示:

復制代碼
 1 /*
 2 #!/usr/bin/env gorun
 3 @author :yinzhengjie
 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
 5 EMAIL:y1053419035@qq.com
 6 */
 7 
 8 package main
 9 
10 import "fmt"
11 
12 func MyEcho(yzj interface{}) {
13     fmt.Printf("yzj is of type %T\n", yzj)
14 }
15 
16 func main() {
17     var yzj interface{}    // 空接口的使用,空接口類型的變量可以保存任何類型的值,空格口類型的變量非常類似於弱類型語言中的變量,未被初始化的interface默認初始值為nil。
18     MyEcho(yzj)
19     yzj = 100                //將其類型定義為“int”
20     MyEcho(yzj)
21     yzj = "Golang"            //將其類型定義為“string”
22     MyEcho(yzj)
23 }
24 
25 
26 
27 #以上代碼執行結果如下:
28 yzj is of type <nil>
29 yzj is of type int
30 yzj is of type string
復制代碼

 

布爾值:

1 %t    單詞true或false

整數:

復制代碼
1 %b    表示為二進制
2 %c    該值對應的unicode碼值
3 %d    表示為十進制
4 %o    表示為八進制
5 %q    該值對應的單引號括起來的go語法字符字面值,必要時會采用安全的轉義表示
6 %x    表示為十六進制,使用a-f
7 %X    表示為十六進制,使用A-F
8 %U    表示為Unicode格式:U+1234,等價於"U+%04X"
復制代碼

浮點數、復數的兩個組分:

1 %b    無小數部分、二進制指數的科學計數法,如-123456p-78;參見strconv.FormatFloat %e    科學計數法,如-1234.456e+78 %E    科學計數法,如-1234.456E+78 %f    有小數部分但無指數部分,如123.456 %F    等價於%f %g    根據實際情況采用%e或%f格式(以獲得更簡潔、准確的輸出)
2 %G    根據實際情況采用%E或%F格式(以獲得更簡潔、准確的輸出)

字符串和[]byte:

1 %s    直接輸出字符串或者[]byte %q    該值對應的雙引號括起來的go語法字符串字面值,必要時會采用安全的轉義表示
2 %x    每個字節用兩字符十六進制數表示(使用a-f)
3 %X    每個字節用兩字符十六進制數表示(使用A-F)

指針:

1 %p    表示為十六進制,並加上前導的0x

沒有verb %u。整數如果是無符號類型自然輸出也是無符號的。類似的,也沒有必要指定操作數的尺寸(int8,int64)。

寬度通過一個緊跟在百分號后面的十進制數指定,如果未指定寬度,則表示值時除必需之外不作填充。精度通過(可能有的)寬度后跟點號后跟的十進制數指定。如果未指定精度,會使用默認精度;如果點號后沒有跟數字,表示精度為0。舉例如下:

1 %f:    默認寬度,默認精度
2 %9f    寬度9,默認精度
3 %.2f   默認寬度,精度2 %9.2f  寬度9,精度2 %9.f   寬度9,精度0

寬度和精度格式化控制的是Unicode碼值的數量(不同於C的printf,它的這兩個因數指的是字節的數量)。兩者任一個或兩個都可以使用'*'號取代,此時它們的值將被對應的參數(按'*'號和verb出現的順序,即控制其值的參數會出現在要表示的值前面)控制,這個操作數必須是int類型。

對於大多數類型的值,寬度是輸出的最小字符數,如果必要是會用空格填充。對於字符串,寬度是輸出字符數目的最低數量,如果必要會截斷字符串。

對於整數,寬度和精度都設置輸出總長度。采用精度時表示右對齊並用0填充,而寬度默認表示用空格填充。

對於浮點數,寬度設置輸出總長度;精度設置小數部分長度(如果有的話),除了%g/%G,此時精度設置總的數字個數。例如,對數字123.45,格式%6.2f 輸出123.45;格式%.4g輸出123.5。%e和%f的默認精度是6,%g的默認精度是可以將該值區分出來需要的最小數字個數。

對復數,寬度和精度會分別用於實部和虛部,結果用小括號包裹。因此%f用於1.2+3.4i輸出(1.200000+3.400000i)。

其它flag:

復制代碼
1 +    總是輸出數值的正負號;對%q(%+q)會生成全部是ASCII字符的輸出(通過轉義);
2 -    在輸出右邊填充空白而不是默認的左邊(即從默認的右對齊切換為左對齊);
3 #    切換格式:
4       八進制數前加0(%#o),十六進制數前加0x(%#x)或0X(%#X),指針去掉前面的0x(%#p);
5      對%q(%#q),如果strconv.CanBackquote返回真會輸出反引號括起來的未轉義字符串;
6      對%U(%#U),如果字符是可打印的,會在輸出Unicode格式、空格、單引號括起來的go字面值;
7 ' '    對數值,正數前加空格而負數前加負號;
8       對字符串采用%x或%X時(% x或% X)會給各打印的字節之間加空格;
9 0    使用0而不是空格填充,對於數值類型會把填充的0放在正負號后面;
復制代碼

verb會忽略不支持的flag。例如,因為沒有十進制切換模式,所以%#d和%d的輸出是相同的。

對每一個類似Printf的函數,都有對應的Print型函數,該函數不接受格式字符串,就效果上等價於對每一個參數都是用verb %v。另一個變體Println型函數會在各個操作數的輸出之間加空格並在最后換行。

不管verb如何,如果操作數是一個接口值,那么會使用接口內部保管的值,而不是接口,因此:

復制代碼
 1 /*
 2 #!/usr/bin/env gorun
 3 @author :yinzhengjie
 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
 5 EMAIL:y1053419035@qq.com
 6 */
 7 
 8 package main
 9 
10 import "fmt"
11 
12 func main() {
13     var name interface{} = "yinzhengjie"
14     fmt.Printf("My name is %v !\n", name)
15     var age  interface{} = 18
16     fmt.Printf("I am [%d] years old。",age)
17 }
18 
19 
20 
21 #以上代碼執行結果如下:
22 My name is yinzhengjie !
23 I am [18] years old。
復制代碼

除了verb %T和%p之外;對實現了特定接口的操作數會考慮采用特殊的格式化技巧。按應用優先級如下:

1. 如果操作數實現了Formatter接口,會調用該接口的方法。Formatter提供了格式化的控制。

2. 如果verb %v配合flag #使用(%#v),且操作數實現了GoStringer接口,會調用該接口。

如果操作數滿足如下兩條任一條,對於%s、%q、%v、%x、%X五個verb,將考慮:

3. 如果操作數實現了error接口,Error方法會用來生成字符串,隨后將按給出的flag(如果有)和verb格式化。

4. 如果操作數具有String方法,這個方法將被用來生成字符串,然后將按給出的flag(如果有)和verb格式化。

復合類型的操作數,如切片和結構體,格式化動verb遞歸地應用於其每一個成員,而不是作為整體一個操作數使用。因此%q會將[]string的每一個成員括起來,%6.2f會控制浮點數組的每一個元素的格式化。

為了避免可能出現的無窮遞歸,如:

1 type X string
2 func (x X) String() string { return Sprintf("<%s>", x) }

應在遞歸之前轉換值的類型:

1 func (x X) String() string { return Sprintf("<%s>", string(x)) }

顯式指定參數索引:

在Printf、Sprintf、Fprintf三個函數中,默認的行為是對每一個格式化verb依次對應調用時成功傳遞進來的參數。但是,緊跟在verb之前的[n]符號表示應格式化第n個參數(索引從1開始)。同樣的在'*'之前的[n]符號表示采用第n個參數的值作為寬度或精度。在處理完方括號表達式[n]后,除非另有指示,會接着處理參數n+1,n+2……(就是說移動了當前處理位置)。例如:

1 fmt.Sprintf("%[2]d %[1]d\n", 11, 22)

會生成"22 11",而:

1 fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6),

等價於:

1 fmt.Sprintf("%6.2f", 12.0),

會生成" 12.00"。因為顯式的索引會影響隨后的verb,這種符號可以通過重設索引用於多次打印同一個值:

1 fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)

會生成"16 17 0x10 0x11"

格式化錯誤:

如果給某個verb提供了非法的參數,如給%d提供了一個字符串,生成的字符串會包含該問題的描述,如下所例:

復制代碼
 1 錯誤的類型或未知的verb:%!verb(type=value)
 2     Printf("%d", hi):          %!d(string=hi)
 3 太多參數(采用索引時會失效):%!(EXTRA type=value)
 4     Printf("hi", "guys"):      hi%!(EXTRA string=guys)
 5 太少參數: %!verb(MISSING)
 6     Printf("hi%d"):            hi %!d(MISSING)
 7 寬度/精度不是整數值:%!(BADWIDTH) or %!(BADPREC)
 8     Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
 9     Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
10 沒有索引指向的參數:%!(BADINDEX)
11     Printf("%*[2]d", 7):       %!d(BADINDEX)
12     Printf("%.[2]d", 7):       %!d(BADINDEX)
復制代碼

所有的錯誤都以字符串"%!"開始,有時會后跟單個字符(verb標識符),並以加小括弧的描述結束。

如果被print系列函數調用時,Error或String方法觸發了panic,fmt包會根據panic重建錯誤信息,用一個字符串說明該panic經過了fmt包。例如,一個String方法調用了panic("bad"),生成的格式化信息差不多是這樣的:

%!s(PANIC=bad)

%!s指示表示錯誤(panic)出現時的使用的verb。

Scanning

一系列類似的函數可以掃描格式化文本以生成值。

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,有如下區別:

1 %p 未實現
2 %T 未實現
3 %e %E %f %F %g %G 效果相同,用於讀取浮點數或復數類型
4 %s %v 用在字符串時會讀取空白分隔的一個片段
5 flag # 和 + 未實現

在無格式化verb或verb %v下掃描整數時會接受常用的進制設置前綴0(八進制)和0x(十六進制)。

寬度會在輸入文本中被使用(%5s表示最多讀取5個rune來生成一個字符串),但沒有使用精度的語法(沒有%5.2f,只有%5f)。

當使用格式字符串進行掃描時,多個連續的空白字符(除了換行符)在輸出和輸出中都被等價於一個空白符。在此前提下,格式字符串中的文本必須匹配輸入的文本;如果不匹配掃描會中止,函數的整數返回值說明已經掃描並填寫的參數個數。

在所有的掃描函數里,\r\n都被視為\n。

在所有的掃描函數里,如果一個操作數實現了Scan方法(或者說,它實現了Scanner接口),將會使用該接口為該操作數掃描文本。另外,如果如果掃描到(准備填寫)的參數比提供的參數個數少,會返回一個錯誤。

提供的所有參數必須為指針或者實現了Scanner接口。注意:Fscan等函數可能會在返回前多讀取一個rune,這導致多次調用這些函數時可能會跳過部分輸入。只有在輸入里各值之間沒有空白時,會出現問題。如果提供給Fscan等函數的io.Reader接口實現了ReadRune方法,將使用該方法讀取字符。如果該io.Reader接口還實現了UnreadRune方法,將是使用該方法保存字符,這樣可以使成功執行的Fscan等函數不會丟失數據。如果要給一個沒有這兩個方法的io.Reader接口提供這兩個方法,使用bufio.NewReader。

 

type Stringer

1 type Stringer interface { String() string }

實現了Stringer接口的類型(即有String方法),定義了該類型值的原始顯示。當采用任何接受字符的verb(%v %s %q %x %X)動作格式化一個操作數時,或者被不使用格式字符串如Print函數打印操作數時,會調用String方法來生成輸出的文本。

 

type GoStringer

1 type GoStringer interface { GoString() string }

實現了GoStringer接口的類型(即有GoString方法),定義了該類型值的go語法表示。當采用verb %#v格式化一個操作數時,會調用GoString方法來生成輸出的文本。

type State

1 type State interface { // Write方法用來寫入格式化的文本 Write(b []byte) (ret int, err error) // Width返回寬度值,及其是否被設置 Width() (wid int, ok bool) // Precision返回精度值,及其是否被設置 Precision() (prec int, ok bool) // Flag報告是否設置了flag c(一個字符,如+、-、#等) Flag(c int) bool }
2 State代表一個傳遞給自定義Formatter接口的Format方法的打印環境。它實現了io.Writer接口用來寫入格式化的文本,還提供了該操作數

State代表一個傳遞給自定義Formatter接口的Format方法的打印環境。它實現了io.Writer接口用來寫入格式化的文本,還提供了該操作數的格式字符串指定的選項和寬度、精度信息(通過調用方法)。

type Formatter

1 type Formatter interface { // c為verb,f提供verb的細節信息和Write方法用於寫入生成的格式化文本 Format(f State, c rune)
2 }

實現了Formatter接口的類型可以定制自己的格式化輸出。Format方法的實現內部可以調用Sprint或Fprint等函數來生成自身的輸出。

type ScanState

復制代碼
1 type ScanState interface { // 從輸入讀取下一個rune(Unicode碼值),在讀取超過指定寬度時會返回EOF // 如果在Scanln、Fscanln或Sscanln中被調用,本方法會在返回第一個'\n'后再次調用時返回EOF ReadRune() (r rune, size int, err error) // UnreadRune方法讓下一次調用ReadRune時返回上一次返回的rune且不移動讀取位置 UnreadRune() error // SkipSpace方法跳過輸入中的空白,換行被視為空白 // 在Scanln、Fscanln或Sscanln中被調用時,換行被視為EOF SkipSpace() // 方法從輸入中依次讀取rune並用f測試,直到f返回假;將讀取的rune組織為一個[]byte切片返回。 // 如果skipSpace參數為真,本方法會先跳過輸入中的空白。 // 如果f為nil,會使用!unicode.IsSpace(c);就是說返回值token將為一串非空字符。 // 換行被視為空白,在Scanln、Fscanln或Sscanln中被調用時,換行被視為EOF。 // 返回的切片指向一個共享內存,可能被下一次調用Token方法時重寫; // 或被使用該Scanstate的另一個Scan函數重寫;或者在本次調用的Scan方法返回時重寫。 Token(skipSpace bool, f func(rune) bool) (token []byte, err error) // Width返回返回寬度值,及其是否被設置。單位是unicode碼值。 Width() (wid int, ok bool) // 因為本接口實現了ReadRune方法,Read方法永遠不應被在Scanner接口中使用。 // 一個合法的ScanStat接口實現可能會選擇讓本方法總是返回錯誤。 Read(buf []byte) (n int, err error)
2 }
復制代碼

ScanState代表一個將傳遞給Scanner接口的Scan方法的掃描環境。 Scan函數中,可以進行一次一個rune的掃描,或者使用Token方法獲得下一個token(比如空白分隔的token)。

type Scanner

1 type Scanner interface { Scan(state ScanState, verb rune) error }

當Scan、Scanf、Scanln或類似函數接受實現了Scanner接口的類型(其Scan方法的receiver必須是指針,該方法從輸入讀取該類型值的字符串表示並將結果寫入receiver)的指針作為參數時,會調用其Scan方法進行定制的掃描。

func Printf

1 func Printf(format string, a ...interface{}) (n int, err error)

Printf根據format參數生成格式化的字符串並寫入標准輸出。返回寫入的字節數和遇到的任何錯誤。

func Fprintf

1 func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

Fprintf根據format參數生成格式化的字符串並寫入w。返回寫入的字節數和遇到的任何錯誤。

func Sprintf

1 func Sprintf(format string, a ...interface{}) string

Sprintf根據format參數生成格式化的字符串並返回該字符串。

func Print

1 func Print(a ...interface{}) (n int, err error)

Print采用默認格式將其參數格式化並寫入標准輸出。如果兩個相鄰的參數都不是字符串,會在它們的輸出之間添加空格。返回寫入的字節數和遇到的任何錯誤。

func Fprint

1 func Fprint(w io.Writer, a ...interface{}) (n int, err error)

Fprint采用默認格式將其參數格式化並寫入w。如果兩個相鄰的參數都不是字符串,會在它們的輸出之間添加空格。返回寫入的字節數和遇到的任何錯誤。

func Sprint

1 func Sprint(a ...interface{}) string

Sprint采用默認格式將其參數格式化,串聯所有輸出生成並返回一個字符串。如果兩個相鄰的參數都不是字符串,會在它們的輸出之間添加空格。

func Println

1 func Println(a ...interface{}) (n int, err error)

Println采用默認格式將其參數格式化並寫入標准輸出。總是會在相鄰參數的輸出之間添加空格並在輸出結束后添加換行符。返回寫入的字節數和遇到的任何錯誤。

func Fprintln

1 func Fprintln(w io.Writer, a ...interface{}) (n int, err error)

Fprintln采用默認格式將其參數格式化並寫入w。總是會在相鄰參數的輸出之間添加空格並在輸出結束后添加換行符。返回寫入的字節數和遇到的任何錯誤。

func Sprintln

1 func Sprintln(a ...interface{}) string

Sprintln采用默認格式將其參數格式化,串聯所有輸出生成並返回一個字符串。總是會在相鄰參數的輸出之間添加空格並在輸出結束后添加換行符。

func Errorf

1 func Errorf(format string, a ...interface{}) error

Errorf根據format參數生成格式化字符串並返回一個包含該字符串的錯誤。

func Scanf

1 func Scanf(format string, a ...interface{}) (n int, err error)

Scanf從標准輸入掃描文本,根據format 參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。返回成功掃描的條目個數和遇到的任何錯誤。

func Fscanf

1 func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)

Fscanf從r掃描文本,根據format 參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。返回成功掃描的條目個數和遇到的任何錯誤。

func Sscanf

1 func Sscanf(str string, format string, a ...interface{}) (n int, err error)

Sscanf從字符串str掃描文本,根據format 參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。返回成功掃描的條目個數和遇到的任何錯誤。

func Scan

1 func Scan(a ...interface{}) (n int, err error)

Scan從標准輸入掃描文本,將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。換行視為空白。返回成功掃描的條目個數和遇到的任何錯誤。如果讀取的條目比提供的參數少,會返回一個錯誤報告原因。

func Fscan

1 func Fscan(r io.Reader, a ...interface{}) (n int, err error)

Fscan從r掃描文本,將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。換行視為空白。返回成功掃描的條目個數和遇到的任何錯誤。如果讀取的條目比提供的參數少,會返回一個錯誤報告原因。

func Sscan

1 func Sscan(str string, a ...interface{}) (n int, err error)

Sscan從字符串str掃描文本,將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。換行視為空白。返回成功掃描的條目個數和遇到的任何錯誤。如果讀取的條目比提供的參數少,會返回一個錯誤報告原因。

func Scanln

1 func Scanln(a ...interface{}) (n int, err error)

Scanln類似Scan,但會在換行時才停止掃描。最后一個條目后必須有換行或者到達結束位置。

func Fscanln

1 func Fscanln(r io.Reader, a ...interface{}) (n int, err error)

Fscanln類似Fscan,但會在換行時才停止掃描。最后一個條目后必須有換行或者到達結束位置。

func Sscanln

1 func Sscanln(str string, a ...interface{}) (n int, err error)

Sscanln類似Sscan,但會在換行時才停止掃描。最后一個條目后必須有換行或者到達結束位置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM