fmt 包实现了格式化 I/O,其功能类似于 C 的 printf 和 scanf。主要分为向外输出内容和获取输入内容两大部分https://pkg.go.dev/fmt
1、输出 1.1、输出到控制台 fmt.Print
系列 print 有三个相关的函数:
1 2 3 4 5 6 7 8 9 func Print (a ...any) (n int , err error) { return Fprint(os.Stdout, a...) }func Println (a ...any) (n int , err error) { return Fprintln(os.Stdout, a...) }func Printf (format string , a ...any) (n int , err error) { return Fprintf(os.Stdout, format, a...) }
可以看到,最终调用的都是 Fprint
系列,os.Stdout
代表标准输出,即控制台输出
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport ( "fmt" "testing" )func TestPrint (t *testing.T) { fmt.Print("我是控制台打印,我不换行 可以自己控制换行" ) }func TestPrintln (t *testing.T) { fmt.Println("我是控制台打印,我换行" ) }func TestPrintf (t *testing.T) { fmt.Printf("我是控制台打印,%s \n" , "这是格式化占位符信息,可以自己控制换行" ) }
1.2、格式化占位符 1.2.1、通用占位符
占位符
说明
%v
值的默认格式表示
%+v
类似%v,但输出结构体时会添加字段名
%#v
值的Go语法表示
%T
打印值的类型
%%
百分号
1 2 3 4 5 6 7 8 9 10 11 type User struct { Id int64 }func TestPrintf1 (t *testing.T) { user := &User{Id: 1 } fmt.Printf("%v\n" , user) fmt.Printf("%+v\n" , user) fmt.Printf("%#v\n" , user) fmt.Printf("%T\n" , user) fmt.Printf("%%\n" ) }
1.2.2、布尔型
1 2 3 func TestPrintf2 (t *testing.T) { fmt.Printf("%t\n" , true ) }
1.2.3、整型
占位符
说明
%b
表示为二进制
%c
该值对应的unicode码值
%d
表示为十进制
%o
表示为八进制
%x
表示为十六进制,使用a-f
%X
表示为十六进制,使用A-F
%U
表示为Unicode格式:U+1234,等价于”U+%04X”
%q
该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
1 2 3 4 5 6 7 8 9 10 11 12 13 func TestPrintf3 (t *testing.T) { n := 180 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) fmt.Printf("%U\n" , n) a := 96 fmt.Printf("%q\n" , a) fmt.Printf("%q\n" , 0x4E2D ) }
1.2.4、浮点数与复数
占位符
说明
%b
无小数部分、二进制指数的科学计数法,如-123456p-78
%e
科学计数法,如-1234.456e+78
%E
科学计数法,如-1234.456E+78
%f
有小数部分但无指数部分,如123.456
%F
等价于%f
%g
根据实际情况采用%e或%f格式(以获得更简洁、准确的输出)
%G
根据实际情况采用%E或%F格式(以获得更简洁、准确的输出)
1 2 3 4 5 6 7 8 9 10 func TestPrintf4 (t *testing.T) { f := 18.54 fmt.Printf("%b\n" , f) fmt.Printf("%e\n" , f) fmt.Printf("%E\n" , f) fmt.Printf("%f\n" , f) fmt.Printf("%F\n" , f) fmt.Printf("%g\n" , f) fmt.Printf("%G\n" , f) }
1.2.5、字符串和[]byte
占位符
说明
%s
直接输出字符串或者[]byte
%q
该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示
%x
每个字节用两字符十六进制数表示(使用a-f
%X
每个字节用两字符十六进制数表示(使用A-F)
1 2 3 4 5 6 7 8 9 func TestPrintf5 (t *testing.T) { s := "我是字符串" b := []byte {65 , 66 , 67 } fmt.Printf("%s\n" , s) fmt.Printf("%s\n" , b) fmt.Printf("%q\n" , s) fmt.Printf("%x\n" , s) fmt.Printf("%X\n" , s) }
1.2.6、指针
占位符
说明
%p
表示为十六进制,并加上前导的0x
1.2.7、宽度标识符 宽度
通过一个紧跟在百分号后面的十进制数指定,如果未指定宽度,则表示值时除必需之外不作填充。
精度
通过(可选的)宽度后跟点号后跟的十进制数指定。如果未指定精度,会使用默认精度;如果点号后没有跟数字,表示精度为0。
占位符
说明
%f
默认宽度,默认精度
%10f
宽度9,默认精度
%.2f
默认宽度,精度2
%10.2f
宽度9,精度2
%10.f
宽度9,精度0
1 2 3 4 5 6 7 8 9 func TestPrintf6 (t *testing.T) { n := 13.14 fmt.Printf("%f\n" , n) fmt.Printf("%10f\n" , n) fmt.Printf("%10s\n" , "我是字符串" ) fmt.Printf("%.2f\n" , n) fmt.Printf("%10.2f\n" , n) fmt.Printf("%10.f\n" , n) }
1.2.8、其他falg
占位符
说明
+
总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义);
空格
对数值,正数前加空格而负数前加负号;对字符串采用%x或%X时(% x或% X)会给各打印的字节之间加空格
-
在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐);
#
八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X),指针去掉前面的0x(%#p)对%q(%#q),对%U(%#U)会输出空格和单引号括起来的go字面值;
0
使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面;
1 2 3 4 5 6 7 8 9 10 func TestPrintf7 (t *testing.T) { s := "我是字符串" fmt.Printf("% d\n" , 10 ) fmt.Printf("%s\n" , s) fmt.Printf("%10s\n" , s) fmt.Printf("%-10s\n" , s) fmt.Printf("%10.2f\n" , 10.14 ) fmt.Printf("%-10.2f\n" , 10.14 ) fmt.Printf("%010s\n" , s) }
1.3、输出到文件 fmt.Fprint
系列 将内容输出到一个io.Writer接口类型的变量w中。
方法名
描述
Fprintln
功能和Println
一样,但可以输出到文件
Fprintf
功能和Printf
一样,但可以输出到文件
Fprint
功能和Print
一样,但可以输出到文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func Fprint (w io.Writer, a ...any) (n int , err error) { p := newPrinter() p.doPrint(a) n, err = w.Write(p.buf) p.free() return }func Fprintf (w io.Writer, format string , a ...any) (n int , err error) { p := newPrinter() p.doPrintf(format, a) n, err = w.Write(p.buf) p.free() return }func Fprintln (w io.Writer, a ...any) (n int , err error) { p := newPrinter() p.doPrintln(a) n, err = w.Write(p.buf) p.free() return }
n
是写入的字节数量,err
是返回的错误
一般用在写文件中。
1 2 3 func TestFPrint (t *testing.T) { fmt.Fprintln(os.Stdout, "向标准输出写入字符串" ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 s := os.FileMode(0777 ).String() fmt.Println(s)
1 2 3 4 5 func TestFPrint1 (t *testing.T) { file, _ := os.OpenFile("test.txt" , os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644 ) fmt.Fprintln(file, "追加写入" ) file.Close() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport ( "fmt" "net/http" )func main () { http.ListenAndServe(":8088" , &MyHandler{}) }type MyHandler struct { }func (*MyHandler) ServeHTTP (w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "我是http返回的信息" ) }
1.4、生成字符串 fmt.Sprint
系列
方法名
描述
Sprintf
同Printf
一样,但是结果不输出到控制台,而是直接返回
Sprint
同Print
一样,但是结果不输出到控制台,而是直接返回
Sprintln
同Println
一样,但是结果不输出到控制台,而是直接返回
把传入的数据生成并返回一个字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func Sprint (a ...any) string { p := newPrinter() p.doPrint(a) s := string (p.buf) p.free() return s }func Sprintf (format string , a ...any) string { p := newPrinter() p.doPrintf(format, a) s := string (p.buf) p.free() return s }func Sprintln (a ...any) string { p := newPrinter() p.doPrintln(a) s := string (p.buf) p.free() return s }
示例:
1 2 3 4 5 6 7 8 func TestSPrint (t *testing.T) { s1 := fmt.Sprint("张三" ) name := "张三" age := 18 s2 := fmt.Sprintf("name:%s,age:%d" , name, age) s3 := fmt.Sprintln("张三" ) fmt.Println(s1, s2, s3) }
1.5、生成错误类型 fmt.Errorf
系列 根据 format 参数生成格式化字符串并返回一个包含该字符串的错误
1 func Errorf (format string , a ...any) error
示例
1 2 3 4 5 6 func TestErrorf (t *testing.T) { err := fmt.Errorf("用户名格式不正确:%s" , "@#¥哈哈" ) if err != nil { panic (err) } }
2、输入 2.1、fmt.Scan 定义:
1 2 3 func Scan (a ...any) (n int , err error) { return Fscan(os.Stdin, a...) }
含义:从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符
返回值:本函数返回成功扫描的数据个数(n)和遇到的任何错误(error)
1 2 3 4 5 6 7 8 9 10 11 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) }
2.2、fmt.Scanf 1 2 3 func Scanf (format string , a ...any) (n int , err error) { return Fscanf(os.Stdin, format, a...) }
实际使用的是 Fscanf
。以 format 定义的格式来进行输入
1 2 3 4 5 6 7 8 9 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) }
2.3、fmt.Scanln 1 2 3 func Scanln (a ...any) (n int , err error) { return Fscanln(os.Stdin, a...) }
1 2 3 4 5 6 7 8 9 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) }
遇到回车就结束扫描
2.4、fmt.Fsanf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func Fscanf (r io.Reader, format string , a ...any) (n int , err error) { s, old := newScanState(r, false , false ) n, err = s.doScanf(format, a) s.free(old) return }func Fscan (r io.Reader, a ...any) (n int , err error) { s, old := newScanState(r, true , false ) n, err = s.doScan(a) s.free(old) return }func Fscanln (r io.Reader, a ...any) (n int , err error) { s, old := newScanState(r, false , true ) n, err = s.doScan(a) s.free(old) return }
将内容从一个io.Reader接口类型的变量r中读取出来,将连续的以空格分隔的值存储到由格式确定的连续的参数中
r io.Reader
: 此参数包含扫描的指定文本。
format string
: 此参数包含用于接收元素的不同格式。
a …any
: 此参数是每个元素的指定变量。
返回值: 它返回成功解析的项目数和错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func main () { var ( name string age int married bool ) r := strings.NewReader("10 false 张三" ) n, err := fmt.Fscanf(r, "%d %t %s" , &age, &married, &name) if err != nil { fmt.Fprintf(os.Stderr, "Fscanf:%v\n" , err) } fmt.Println(name, age, married) fmt.Println(n) }