Go fmt库


Go fmt库


正文

fmt库的包:

主要分为向外输出内容和获取输入内容两大部分

输出

fmt.Print有几个变种:

  • Print: 输出到控制台,不接受任何格式化操作
  • Println: 输出到控制台并换行
  • Printf : 只可以打印出格式化的字符串。只可以直接输出字符串类型的变量(不可以输出别的类型)
  • Sprintf:格式化并返回一个字符串而不带任何输出
  • Fprintf:来格式化并输出到 io.Writers 而不是 os.Stdout

通用的占位符

  • %v 值的默认格式
  • %+v 类似%v,但输出结构体时会添加字段名
  • %#v 相应值的Go语法表示
  • %T 相应值的类型的Go语法表示
  • %% 百分号,字面上的%,非占位符含义

如:

package main

import (
    "fmt"
)

type User struct {
    Name string
    Age  int
}

func main() {
    user := User{"xiaoming", 13}
    fmt.Println(user)
    //Go默认形式
    fmt.Printf("%v",user)
    fmt.Println()
    //输出字段名和字段值形式
    fmt.Printf("%+v",user)
    fmt.Println()
    //类型+值对象
    fmt.Printf("%#v",user)
    fmt.Println()
    //值类型的Go语法表示形式
    fmt.Printf("%T",user)
    fmt.Println()
    fmt.Printf("%%")
}

输出:

{xiaoming 13}
{xiaoming 13}
{Name:xiaoming Age:13}
main.User{Name:"xiaoming", Age:13}
main.User
%

常用类型

The verbs:
    General:
        %v    the value in a default format
            when printing structs, the plus flag (%+v) adds field names
        %#v    a Go-syntax representation of the value
        %T    a Go-syntax representation of the type of the value
        %%    a literal percent sign; consumes no value

    Boolean:
        %t    the word true or false
    Integer:
        %b    base 2
        %c    the character represented by the corresponding Unicode code point
        %d    base 10
        %o    base 8
        %O    base 8 with 0o prefix
        %q    a single-quoted character literal safely escaped with Go syntax.
        %x    base 16, with lower-case letters for a-f
        %X    base 16, with upper-case letters for A-F
        %U    Unicode format: U+1234; same as "U+%04X"
    Floating-point and complex constituents:
        %b    decimalless scientific notation with exponent a power of two,
            in the manner of strconv.FormatFloat with the 'b' format,
            e.g. -123456p-78
        %e    scientific notation, e.g. -1.234456e+78
        %E    scientific notation, e.g. -1.234456E+78
        %f    decimal point but no exponent, e.g. 123.456
        %F    synonym for %f
        %g    %e for large exponents, %f otherwise. Precision is discussed below.
        %G    %E for large exponents, %F otherwise
        %x    hexadecimal notation (with decimal power of two exponent), e.g. -0x1.23abcp+20
        %X    upper-case hexadecimal notation, e.g. -0X1.23ABCP+20
    String and slice of bytes (treated equivalently with these verbs):
        %s    the uninterpreted bytes of the string or slice
        %q    a double-quoted string safely escaped with Go syntax
        %x    base 16, lower-case, two characters per byte
        %X    base 16, upper-case, two characters per byte
    Slice:
        %p    address of 0th element in base 16 notation, with leading 0x
    Pointer:
        %p    base 16 notation, with leading 0x
        The %b, %d, %o, %x and %X verbs also work with pointers,
        formatting the value exactly as if it were an integer.

    The default format for %v is:
        bool:                    %t
        int, int8 etc.:          %d
        uint, uint8 etc.:        %d, %#x if printed with %#v
        float32, complex64, etc: %g
        string:                  %s
        chan:                    %p
        pointer:                 %p
    For compound objects, the elements are printed using these rules, recursively,
    laid out like this:
        struct:             {field0 field1 ...}
        array, slice:       [elem0 elem1 ...]
        maps:               map[key1:value1 key2:value2 ...]
        pointer to above:   &{}, &[], &map[]

    Width is specified by an optional decimal number immediately preceding the verb.
    If absent, the width is whatever is necessary to represent the value.
    Precision is specified after the (optional) width by a period followed by a
    decimal number. If no period is present, a default precision is used.
    A period with no following number specifies a precision of zero.
    Examples:
        %f     default width, default precision
        %9f    width 9, default precision
        %.2f   default width, precision 2
        %9.2f  width 9, precision 2
        %9.f   width 9, precision 0
        
Other flags:
    +    always print a sign for numeric values;
        guarantee ASCII-only output for %q (%+q)
    -    pad with spaces on the right rather than the left (left-justify the field)
    #    alternate format: add leading 0b for binary (%#b), 0 for octal (%#o),
        0x or 0X for hex (%#x or %#X); suppress 0x for %p (%#p);
        for %q, print a raw (backquoted) string if strconv.CanBackquote
        returns true;
        always print a decimal point for %e, %E, %f, %F, %g and %G;
        do not remove trailing zeros for %g and %G;
        write e.g. U+0078 'x' if the character is printable for %U (%#U).
    ' '    (space) leave a space for elided sign in numbers (% d);
        put spaces between bytes printing strings or slices in hex (% x, % X)
    0    pad with leading zeros rather than spaces;
        for numbers, this moves the padding after the sign

解说

解说一

Print() 函数将参数列表 a 中的各个参数转换为字符串并写入到标准输出中。

非字符串参数之间会添加空格,返回写入的字节数。

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

Println() 函数功能类似 Print,只不过最后会添加一个换行符。

所有参数之间会添加空格,返回写入的字节数。

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

Printf() 函数将参数列表 a 填写到格式字符串 format 的占位符中。

填写后的结果写入到标准输出中,返回写入的字节数。

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

以下三个函数功能同上面三个函数(Print()、Println()、Printf()),只不过将转换结果写入到 w 中。

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

以下三个函数功能同上面三个函数(Print()、Println()、Printf()),只不过将转换结果以字符串形式返回。

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

以下函数功能同 Sprintf() 函数,只不过结果字符串被包装成了 error 类型。

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

实例:

func main() {
    fmt.Print("a", "b", 1, 2, 3, "c", "d", "\n")
    fmt.Println("a", "b", 1, 2, 3, "c", "d")
    fmt.Printf("ab %d %d %d cd\n", 1, 2, 3)
    // ab1 2 3cd
    // a b 1 2 3 c d
    // ab 1 2 3 cd

    if err := percent(30, 70, 90, 160); err != nil {
        fmt.Println(err)
    }
    // 30%
    // 70%
    // 90%
    // 数值 160 超出范围(100)
}

func percent(i ...int) error {
    for _, n := range i {
        if n > 100 {
            return fmt.Errorf("数值 %d 超出范围(100)", n)
        }
        fmt.Print(n, "%\n")
    }
    return nil
}

Formatter 由自定义类型实现,用于实现该类型的自定义格式化过程。

当格式化器需要格式化该类型的变量时,会调用其 Format 方法。

type Formatter interface {
    // f 用于获取占位符的旗标、宽度、精度等信息,也用于输出格式化的结果
    // c 是占位符中的动词
    Format(f State, c rune)
}

由格式化器(Print 之类的函数)实现,用于给自定义格式化过程提供信息:

type State interface {
    // Formatter 通过 Write 方法将格式化结果写入格式化器中,以便输出。
    Write(b []byte) (ret int, err error)
    // Formatter 通过 Width 方法获取占位符中的宽度信息及其是否被设置。
    Width() (wid int, ok bool)
    // Formatter 通过 Precision 方法获取占位符中的精度信息及其是否被设置。
    Precision() (prec int, ok bool)
    // Formatter 通过 Flag 方法获取占位符中的旗标[+- 0#]是否被设置。
    Flag(c int) bool
}

Stringer 由自定义类型实现,用于实现该类型的自定义格式化过程。

当格式化器需要输出该类型的字符串格式时就会调用其 String 方法。

type Stringer interface {
    String() string
}

Stringer 由自定义类型实现,用于实现该类型的自定义格式化过程。

当格式化器需要输出该类型的 Go 语法字符串(%#v)时就会调用其 String 方法。

type GoStringer interface {
    GoString() string
}

实例:

type Ustr string

func (us Ustr) String() string {
    return strings.ToUpper(string(us))
}

func (us Ustr) GoString() string {
    return `"` + strings.ToUpper(string(us)) + `"`
}

func (u Ustr) Format(f fmt.State, c rune) {
    write := func(s string) {
        f.Write([]byte(s))
    }
    switch c {
    case 'm', 'M':
        write("旗标:[")
        for s := "+- 0#"; len(s) > 0; s = s[1:] {
            if f.Flag(int(s[0])) {
                write(s[:1])
            }
        }
        write("]")
        if v, ok := f.Width(); ok {
            write(" | 宽度:" + strconv.FormatInt(int64(v), 10))
        }
        if v, ok := f.Precision(); ok {
            write(" | 精度:" + strconv.FormatInt(int64(v), 10))
        }
    case 's', 'v': // 如果使用 Format 函数,则必须自己处理所有格式,包括 %#v
        if c == 'v' && f.Flag('#') {
            write(u.GoString())
        } else {
            write(u.String())
        }
    default: // 如果使用 Format 函数,则必须自己处理默认输出
        write("无效格式:" + string(c))
    }
}

func main() {
    u := Ustr("Hello World!")
    // "-" 标记和 "0" 标记不能同时存在
    fmt.Printf("%-+ 0#8.5m\n", u) // 旗标:[+- #] | 宽度:8 | 精度:5
    fmt.Printf("%+ 0#8.5M\n", u)  // 旗标:[+ 0#] | 宽度:8 | 精度:5
    fmt.Println(u)                // HELLO WORLD!
    fmt.Printf("%s\n", u)         // HELLO WORLD!
    fmt.Printf("%#v\n", u)        // "HELLO WORLD!"
    fmt.Printf("%d\n", u)         // 无效格式:d
}

Scan 从标准输入中读取数据,并将数据用空白分割并解析后存入 a 提供的变量中(换行符会被当作空白处理),变量必须以指针传入。

当读到 EOF 或所有变量都填写完毕则停止扫描。

返回成功解析的参数数量。

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

Scanln 和 Scan 类似,只不过遇到换行符就停止扫描。

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

Scanf 从标准输入中读取数据,并根据格式字符串 format 对数据进行解析,将解析结果存入参数 a 所提供的变量中,变量必须以指针传入。

输入端的换行符必须和 format 中的换行符相对应(如果格式字符串中有换行符,则输入端必须输入相应的换行符)。

占位符 %c 总是匹配下一个字符,包括空白,比如空格符、制表符、换行符。

返回成功解析的参数数量。

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

以下三个函数功能同上面三个函数,只不过从 r 中读取数据。

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)

以下三个函数功能同上面三个函数,只不过从 str 中读取数据。

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)

实例:

// 对于 Scan 而言,回车视为空白
func main() {
    a, b, c := "", 0, false
    fmt.Scan(&a, &b, &c)
    fmt.Println(a, b, c)
    // 在终端执行后,输入 abc 1 回车 true 回车
    // 结果 abc 1 true
}

// 对于 Scanln 而言,回车结束扫描
func main() {
    a, b, c := "", 0, false
    fmt.Scanln(&a, &b, &c)
    fmt.Println(a, b, c)
    // 在终端执行后,输入 abc 1 true 回车
    // 结果 abc 1 true
}

// 格式字符串可以指定宽度
func main() {
    a, b, c := "", 0, false
    fmt.Scanf("%4s%d%t", &a, &b, &c)
    fmt.Println(a, b, c)
    // 在终端执行后,输入 1234567true 回车
    // 结果 1234 567 true
}

Scanner 由自定义类型实现,用于实现该类型的自定义扫描过程。

当扫描器需要解析该类型的数据时,会调用其 Scan 方法。

type Scanner interface {
    // state 用于获取占位符中的宽度信息,也用于从扫描器中读取数据进行解析。
    // verb 是占位符中的动词
    Scan(state ScanState, verb rune) error
}

由扫描器(Scan 之类的函数)实现,用于给自定义扫描过程提供数据和信息。

type ScanState interface {
    // ReadRune 从扫描器中读取一个字符,如果用在 Scanln 类的扫描器中,
    // 则该方法会在读到第一个换行符之后或读到指定宽度之后返回 EOF。
    // 返回“读取的字符”和“字符编码所占用的字节数”
    ReadRune() (r rune, size int, err error)
    // UnreadRune 撤消最后一次的 ReadRune 操作,
    // 使下次的 ReadRune 操作得到与前一次 ReadRune 相同的结果。
    UnreadRune() error
    // SkipSpace 为 Scan 方法提供跳过开头空白的能力。
    // 根据扫描器的不同(Scan 或 Scanln)决定是否跳过换行符。
    SkipSpace()
    // Token 用于从扫描器中读取符合要求的字符串,
    // Token 从扫描器中读取连续的符合 f(c) 的字符 c,准备解析。
    // 如果 f 为 nil,则使用 !unicode.IsSpace(c) 代替 f(c)。
    // skipSpace:是否跳过开头的连续空白。返回读取到的数据。
    // 注意:token 指向共享的数据,下次的 Token 操作可能会覆盖本次的结果。
    Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
    // Width 返回占位符中的宽度值以及宽度值是否被设置
    Width() (wid int, ok bool)
    // 因为上面实现了 ReadRune 方法,所以 Read 方法永远不应该被调用。
    // 一个好的 ScanState 应该让 Read 直接返回相应的错误信息。
    Read(buf []byte) (n int, err error)
}

实例:

type Ustr string

func (u *Ustr) Scan(state fmt.ScanState, verb rune) (err error) {
    var s []byte
    switch verb {
    case 'S':
        s, err = state.Token(true, func(c rune) bool { return 'A' <= c && c <= 'Z' })
        if err != nil {
            return
        }
    case 's', 'v':
        s, err = state.Token(true, func(c rune) bool { return 'a' <= c && c <= 'z' })
        if err != nil {
            return
        }
    default:
        return fmt.Errorf("无效格式:%c", verb)
    }
    *u = Ustr(s)
    return nil
}

func main() {
    var a, b, c, d, e Ustr
    n, err := fmt.Scanf("%3S%S%3s%2v%x", &a, &b, &c, &d, &e)
    fmt.Println(a, b, c, d, e)
    fmt.Println(n, err)
    // 在终端执行后,输入 ABCDEFGabcdefg 回车
    // 结果:
    // ABC DEFG abc de
    // 4 无效格式:x
}

1. 输出

1.1 fmt.Print

print 有三个相关的函数:

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...)
}

可以看到,最终调用的都是Fprintf,os.Stdout代表标准输出,即控制台输出

示例:

package main

import (
    "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 打印值的类型
%% 百分号
type User struct {
    Id int64
}
func TestPrintf1(t *testing.T) {
    user := &User{Id: 1}
    fmt.Printf("%v\n", user)    //  &{1}
    fmt.Printf("%+v\n", user)    //  &{Id:1}
    fmt.Printf("%#v\n", user)   //  &main.User{Id:1}
    fmt.Printf("%T\n", user)   //  *main.User
    fmt.Printf("%%\n")  //  %
}

1.2.2 布尔型

占位符 说明
%t true或false
func TestPrintf2(t *testing.T) {
    fmt.Printf("%t\n", true)    //  true
}

1.2.3 整型

占位符 说明
%b 表示为二进制
%c 该值对应的unicode码值
%d 表示为十进制
%o 表示为八进制
%x 表示为十六进制,使用a-f
%X 表示为十六进制,使用A-F
%U 表示为Unicode格式:U+1234,等价于”U+%04X”
%q 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示


func TestPrintf3(t *testing.T) {
    n := 180
    fmt.Printf("%b\n", n)   //  10110100
    fmt.Printf("%c\n", n)   //  ´
    fmt.Printf("%d\n", n)   //  180
    fmt.Printf("%o\n", n)   //  264
    fmt.Printf("%x\n", n)   //  b4
    fmt.Printf("%X\n", n)   //  B4
    fmt.Printf("%U\n", n)   //  U+00B4
    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格式(以获得更简洁、准确的输出)

func TestPrintf4(t *testing.T) {
    f := 18.54
    fmt.Printf("%b\n", f)   //  5218546068215562p-48
    fmt.Printf("%e\n", f)   //  1.854000e+01
    fmt.Printf("%E\n", f)   //  1.854000E+01
    fmt.Printf("%f\n", f)   //  18.540000
    fmt.Printf("%F\n", f)   //  18.540000
    fmt.Printf("%g\n", f)   //  18.54
    fmt.Printf("%G\n", f)   //  18.54
}

1.2.5 字符串和[]byte

占位符 说明
%s 直接输出字符串或者[]byte
%q 该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示
%x 每个字节用两字符十六进制数表示(使用a-f
%X 每个字节用两字符十六进制数表示(使用A-F)

func TestPrintf5(t *testing.T) {
    s := "我是字符串"
    b := []byte{65, 66, 67}   
    fmt.Printf("%s\n", s)   //  我是字符串
    fmt.Printf("%s\n", b)   //  ABC
    fmt.Printf("%q\n", s)   //  "我是字符串"
    fmt.Printf("%x\n", s)   //  e68891e698afe5ad97e7aca6e4b8b2
    fmt.Printf("%X\n", s)   //  E68891E698AFE5AD97E7ACA6E4B8B2
}

1.2.6 指针

占位符 说明
%p 表示为十六进制,并加上前导的0x

1.2.7 宽度标识符

%10.2

宽度通过一个紧跟在百分号后面的十进制数指定,如果未指定宽度,则表示值时除必需之外不作填充。

精度通过(可选的)宽度后跟点号后跟的十进制数指定。如果未指定精度,会使用默认精度;如果点号后没有跟数字,表示精度为0。

占位符 说明
%f 默认宽度,默认精度
%10f 宽度9,默认精度
%.2f 默认宽度,精度2
%10.2f 宽度9,精度2
%10.f 宽度9,精度0

func TestPrintf6(t *testing.T) {
    n := 13.14
    fmt.Printf("%f\n", n)   //  13.140000
    fmt.Printf("%10f\n", n)   //   13.140000
    fmt.Printf("%10s\n", "我是字符串")   //       我是字符串
    fmt.Printf("%.2f\n", n)   //  13.14
    fmt.Printf("%10.2f\n", n)   //       13.14
    fmt.Printf("%10.f\n", n)   //          13
}

1.2.8 其他flag

占位符 说明
+ 总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义);
空格 对数值,正数前加空格而负数前加负号;对字符串采用%x或%X时(% x或% X)会给各打印的字节之间加空格
- 在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐);
# 八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X),指针去掉前面的0x(%#p)对%q(%#q),对%U(%#U)会输出空格和单引号括起来的go字面值;
0 使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面;

func TestPrintf7(t *testing.T) {
    s := "我是字符串"
    fmt.Printf("%  d\n", 10)   //   10
    fmt.Printf("%s\n", s)   //  我是字符串
    fmt.Printf("%10s\n", s)   //       我是字符串
    fmt.Printf("%-10s\n", s)   //  我是字符串
    fmt.Printf("%10.2f\n", 10.14)   //       10.14
    fmt.Printf("%-10.2f\n", 10.14)   //  10.14
    fmt.Printf("%010s\n", s)   //  00000我是字符串
}

1.3 Fprint

将内容输出到一个io.Writer接口类型的变量w中。

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是返回的错误

一般用在写文件中。

func TestFPrint(t *testing.T) {
    fmt.Fprintln(os.Stdout, "向标准输出写入字符串")
}
//  0表示8进制 644表示权限 os.FileMode(0777).String()进行打印
//  - rwx rwx rwx -表示普通文件
//  r表示可读
//  w表示可写
//  x表示可执行
//  第1位:文件属性,一般常用的是"-",表示是普通文件;"d"表示是一个目录。
//  第2~4位:文件所有者的权限rwx (可读/可写/可执行)。
//  第5~7位:文件所属用户组的权限rwx (可读/可写/可执行)。
//  第8~10位:其他人的权限rwx (可读/可写/可执行)。
//  在golang中,可以使用os.FileMode(perm).String()来查看权限标识:
//  os.FileMode(0777).String() //返回 -rwxrwxrwx  111 111 111
//  os.FileMode(0666).String() //返回 -rw-rw-rw-  110 110 110
//  os.FileMode(0644).String() //返回 -rw-r--r-- 
//  0777表示:创建了一个普通文件,所有人拥有所有的读、写、执行权限
//  0666表示:创建了一个普通文件,所有人拥有对该文件的读、写权限,但是都不可执行
//  0644表示:创建了一个普通文件,文件所有者对该文件有读写权限,用户组和其他人只有读权限,都没有执行权限
    s := os.FileMode(0777).String()
    fmt.Println(s)  //  -rwxrwxrwx
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()
}
package main

import (
    "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 Sprint

把传入的数据生成并返回一个字符串

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
}
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)  //  张三 name:张三,age:18 张三
}

1.5 Errorf

根据format参数生成格式化字符串并返回一个包含该字符串的错误

func Errorf(format string, a ...any) error
func TestErrorf(t *testing.T) {
    err := fmt.Errorf("用户名格式不正确:%s", "@#¥哈哈")
    if err != nil {
        panic(err)  //  panic: 用户名格式不正确:@#¥哈哈
    }
}
func TestErrorNew(t *testing.T) {
    err:= errors.New("用户名格式不正确:@#¥哈哈")
    if err != nil {
        panic(err)  //  panic: 用户名格式不正确:@#¥哈哈
    }
}

2. 输入

2.1 fmt.Scan

定义:

func Scan(a ...any) (n int, err error) {
    return Fscan(os.Stdin, a...)
}

含义:

从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符

返回值:

本函数返回成功扫描的数据个数(n)和遇到的任何错误(error)


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

func Scanf(format string, a ...any) (n int, err error) {
    return Fscanf(os.Stdin, format, a...)
}

实际使用的是Fscanf

以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)
}

2.3 fmt.Scanln

func Scanln(a ...any) (n int, err error) {
    return Fscanln(os.Stdin, a...)
}

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

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:此参数是每个元素的指定变量。

返回值:它返回成功解析的项目数和错误


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)
}






参考资料

Go中的fmt几种输出的区别和格式化方式 https://www.cnblogs.com/rickiyang/p/11074171.html


返回