在 Go 语言里打印信息最常用的两个包是fmt和log。fmt更偏向通用格式化输出可以输出到控制台、字符串、文件或其他io.Writer。log更偏向日志输出默认会带时间信息并且提供了打印后退出程序、打印后触发panic等能力。一、fmt 包是什么fmt是 Go 标准库中的格式化输入输出包。使用前需要导入import fmt它最常见的作用是fmt.Println(hello) fmt.Printf(name%s, age%d\n, Tom, 18)二、fmt 的主要打印函数fmt提供了三大类常用打印函数输出到标准输出Print、Println、Printf输出到字符串Sprint、Sprintln、Sprintf输出到指定位置Fprint、Fprintln、Fprintf三、Print、Println、Printf1. fmt.PrintPrint会直接打印内容不会自动换行。package main import fmt func main() { fmt.Print(hello) fmt.Print(world) }输出helloworld如果想要空格需要自己写fmt.Print(hello ) fmt.Print(world)2. fmt.PrintlnPrintln会打印内容并在最后自动换行。多个参数之间会自动加空格。package main import fmt func main() { fmt.Println(hello) fmt.Println(name:, Tom, age:, 18) }输出hello name: Tom age: 183. fmt.PrintfPrintf按照指定格式打印内容。它不会自动换行如果需要换行要手动写\n。package main import fmt func main() { name : Tom age : 18 fmt.Printf(name%s, age%d\n, name, age) }输出nameTom, age18其中%s // 字符串 %d // 十进制整数 \n // 换行四、Sprint、Sprintln、Sprintf这三个函数不会直接打印到控制台而是返回一个字符串。1. fmt.Sprintpackage main import fmt func main() { msg : fmt.Sprint(hello, world) fmt.Println(msg) }输出helloworld2. fmt.SprintlnSprintln会在参数之间加空格并在末尾加换行。package main import fmt func main() { msg : fmt.Sprintln(name:, Tom, age:, 18) fmt.Print(msg) }输出name: Tom age: 183. fmt.SprintfSprintf按格式生成字符串开发中非常常用。package main import fmt func main() { name : Tom age : 18 msg : fmt.Sprintf(name%s, age%d, name, age) fmt.Println(msg) }输出nameTom, age18常见用途是拼接错误信息、生成提示文案、构造路径等。五、Fprint、Fprintln、Fprintf这三个函数会把内容写到指定的io.Writer中。常见的io.Writer有os.Stdout // 标准输出 os.Stderr // 标准错误输出 文件对象 bytes.Buffer1. 打印到标准错误输出package main import ( fmt os ) func main() { err : file not found fmt.Fprintln(os.Stderr, error:, err) }os.Stderr通常用来输出错误信息。命令行程序里一般建议fmt.Println(normal output) // 普通输出 fmt.Fprintln(os.Stderr, error message) // 错误输出2. 写入文件package main import ( fmt os ) func main() { file, err : os.Create(output.txt) if err ! nil { fmt.Println(create file failed:, err) return } defer file.Close() fmt.Fprintln(file, hello file) fmt.Fprintf(file, name%s, age%d\n, Tom, 18) }六、fmt.Printf 的常用格式化参数Printf、Sprintf、Fprintf都会用到格式化参数也叫占位符。格式一般是fmt.Printf(格式字符串, 参数1, 参数2, 参数3)例如fmt.Printf(name%s, age%d\n, Tom, 18)这里%s 对应 Tom %d 对应 18七、通用格式化参数1. %v默认格式%v表示按照默认格式打印值。fmt.Printf(%v\n, 123) fmt.Printf(%v\n, hello) fmt.Printf(%v\n, true)输出123 hello true%v很通用打印错误、整数、字符串、结构体都可以。2. %v打印结构体时带字段名package main import fmt type User struct { Name string Age int } func main() { u : User{Name: Tom, Age: 18} fmt.Printf(%v\n, u) fmt.Printf(%v\n, u) }输出{Tom 18} {Name:Tom Age:18}实际开发中调试结构体最常用fmt.Printf(user%v\n, u)3. %#v打印 Go 语法形式fmt.Printf(%#v\n, u)输出main.User{Name:Tom, Age:18}%#v更适合调试可以看到类型和字段信息。4. %T打印类型fmt.Printf(%T\n, 123) fmt.Printf(%T\n, hello) fmt.Printf(%T\n, u)输出int string main.User5. %%打印百分号fmt.Printf(progress: %d%%\n, 80)输出progress: 80%八、布尔值%t%t用来打印布尔值。ok : true fmt.Printf(ok%t\n, ok)输出oktrue九、整数1. %d十进制整数age : 18 fmt.Printf(age%d\n, age)输出age182. %b二进制fmt.Printf(%b\n, 10)输出10103. %o八进制fmt.Printf(%o\n, 10)输出124. %x 和 %X十六进制fmt.Printf(%x\n, 255) fmt.Printf(%X\n, 255)输出ff FF5. %cUnicode 字符fmt.Printf(%c\n, 65) fmt.Printf(%c\n, 中)输出A 中十、浮点数1. %f普通小数price : 12.3456 fmt.Printf(%f\n, price)输出12.345600默认保留 6 位小数。2. %.2f保留 2 位小数fmt.Printf(%.2f\n, price)输出12.353. %e 和 %E科学计数法fmt.Printf(%e\n, 123456.789) fmt.Printf(%E\n, 123456.789)输出类似1.234568e05 1.234568E054. %g根据情况自动选择格式fmt.Printf(%g\n, 123456.789) fmt.Printf(%g\n, 0.000012345)%g会根据数值大小自动选择普通小数或科学计数法。十一、字符串和字节1. %s字符串name : Tom fmt.Printf(name%s\n, name)输出nameTom2. %q带引号的字符串fmt.Printf(%q\n, hello\nworld)输出hello\nworld%q对调试字符串很有用因为它能看出换行、制表符等特殊字符。3. %x字符串或字节切片的十六进制fmt.Printf(%x\n, Go) fmt.Printf(% x\n, []byte(Go))输出476f 47 6f% x中间有一个空格表示每个字节之间也用空格分隔。十二、指针%p%p用来打印指针地址。age : 18 fmt.Printf(%p\n, age)输出类似0xc0000120c0地址每次运行可能不同。十三、宽度和精度格式化参数还可以控制宽度和精度。1. 宽度fmt.Printf(|%6d|\n, 123) fmt.Printf(|%-6d|\n, 123)输出| 123| |123 |含义%6d // 宽度至少 6默认右对齐 %-6d // 宽度至少 6左对齐2. 补零fmt.Printf(|%06d|\n, 123)输出|000123|3. 小数精度fmt.Printf(%.2f\n, 3.14159) fmt.Printf(%8.2f\n, 3.14159)输出3.14 3.14含义%.2f // 保留 2 位小数 %8.2f // 总宽度至少 8保留 2 位小数十四、错误 err 的打印Go 里的错误类型是error通常变量名叫err。file, err : os.Open(missing.txt) if err ! nil { fmt.Println(err) } defer file.Close()1. fmt.Println(err)fmt.Println(err)会直接打印错误信息。2. fmt.Printf(%v, err)fmt.Printf(error: %v\n, err)%v表示默认格式。对错误来说通常就是调用它的Error()方法。3. fmt.Printf(%s, err)fmt.Printf(error: %s\n, err)%s表示字符串格式。因为error有Error() string方法所以通常也能打印错误文本。实际开发中更推荐fmt.Printf(error: %v\n, err)原因是%v更通用。4. fmt.Errorffmt.Errorf不是直接打印而是创建一个错误。return fmt.Errorf(open file failed: %v, err)如果要包装原始错误推荐使用%wreturn fmt.Errorf(open file failed: %w, err)这样后续可以用errors.Is或errors.As判断错误链。if errors.Is(err, os.ErrNotExist) { fmt.Println(file does not exist) }十五、完整 fmt 示例package main import ( errors fmt os ) type User struct { Name string Age int } func main() { u : User{Name: Tom, Age: 18} fmt.Println(Println:, u) fmt.Printf(default: %v\n, u) fmt.Printf(with fields: %v\n, u) fmt.Printf(go syntax: %#v\n, u) fmt.Printf(type: %T\n, u) fmt.Printf(string: %s\n, hello) fmt.Printf(quoted string: %q\n, hello\nworld) fmt.Printf(int: %d\n, 18) fmt.Printf(binary: %b\n, 10) fmt.Printf(hex: %x\n, 255) fmt.Printf(float: %.2f\n, 3.14159) fmt.Printf(percent: %d%%\n, 80) _, err : os.Open(missing.txt) if err ! nil { fmt.Printf(error: %v\n, err) } err fmt.Errorf(wrap error: %w, errors.New(original error)) fmt.Println(err) }十六、log 包是什么log是 Go 标准库提供的日志包。使用前需要导入import log和fmt相比log更适合记录程序运行信息。默认情况下log会输出到标准错误os.Stderr并且带日期和时间。package main import log func main() { log.Println(server started) }输出类似2026/06/30 12:00:00 server started十七、log 的常用打印函数log常用函数主要有三组Print、Println、PrintfFatal、Fatalln、FatalfPanic、Panicln、Panicf十八、log.Print、log.Println、log.Printf这组函数只是打印日志不会退出程序。1. log.Printpackage main import log func main() { log.Print(hello) log.Print(world) }2. log.Printlnpackage main import log func main() { log.Println(hello) log.Println(name:, Tom, age:, 18) }3. log.Printfpackage main import log func main() { name : Tom age : 18 log.Printf(name%s, age%d, name, age) }log.Printf和fmt.Printf的格式化规则基本一样也使用%s、%d、%v等占位符。十九、log.Fatal、log.Fatalln、log.Fatalf这组函数会先打印日志然后调用os.Exit(1)也就是说程序会立即退出。1. log.Fatalpackage main import log func main() { log.Fatal(program failed) log.Println(this line will not run) }2. log.Fatalfpackage main import log func main() { err : connectDB() if err ! nil { log.Fatalf(connect db failed: %v, err) } } func connectDB() error { return fmt.Errorf(connection refused) }注意上面代码需要同时导入import ( fmt log )Fatal适合用于程序启动阶段的不可恢复错误比如配置读取失败、端口监听失败、数据库连接失败等。不建议在普通业务函数里随便使用log.Fatal因为它会直接结束整个程序。二十、log.Panic、log.Panicln、log.Panicf这组函数会先打印日志然后触发panic。package main import log func main() { log.Panic(something terrible happened) }等价于log.Print(something terrible happened) panic(something terrible happened)panic一般用于程序无法继续运行的严重错误不适合普通错误处理。二十一、设置 log 输出格式1. log.SetFlags默认日志会带日期和时间。可以通过log.SetFlags修改日志前缀格式。package main import log func main() { log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) log.Println(hello) }输出类似2026/06/30 12:00:00 main.go:7: hello常用 flaglog.Ldate // 日期例如 2026/06/30 log.Ltime // 时间例如 12:00:00 log.Lmicroseconds // 微秒 log.Llongfile // 完整文件名和行号 log.Lshortfile // 短文件名和行号 log.LUTC // 使用 UTC 时间 log.Lmsgprefix // 把 prefix 放在日志信息前 log.LstdFlags // 标准格式等于 Ldate | Ltime2. log.SetPrefixSetPrefix可以设置日志前缀。package main import log func main() { log.SetPrefix([myapp] ) log.Println(server started) }输出类似[myapp] 2026/06/30 12:00:00 server started3. log.SetOutputSetOutput可以修改日志输出位置。例如输出到文件package main import ( log os ) func main() { file, err : os.Create(app.log) if err ! nil { log.Fatal(err) } defer file.Close() log.SetOutput(file) log.Println(server started) log.Println(server stopped) }运行后日志会写入app.log。二十二、自定义 Logger除了使用全局的log.Println也可以创建自己的 logger。package main import ( log os ) func main() { infoLogger : log.New(os.Stdout, [INFO] , log.Ldate|log.Ltime) errorLogger : log.New(os.Stderr, [ERROR] , log.Ldate|log.Ltime|log.Lshortfile) infoLogger.Println(server started) errorLogger.Println(file not found) }log.New的参数含义log.New(输出位置, 日志前缀, 日志格式)也就是log.New(io.Writer, prefix string, flag int)二十三、fmt 和 log 怎么选适合用 fmt 的场景fmt.Println(hello) fmt.Printf(name%s\n, name) fmt.Fprintln(os.Stderr, error:, err)适合学习和临时调试命令行程序输出结果格式化生成字符串写入任意io.Writer适合用 log 的场景log.Println(server started) log.Printf(request id%s cost%dms, requestID, cost) log.Fatal(err)适合记录程序运行日志服务端程序输出运行状态需要日期、时间、文件行号程序启动失败后直接退出二十四、常用速查表fmt 函数fmt.Print // 打印不换行 fmt.Println // 打印自动换行参数之间加空格 fmt.Printf // 按格式打印 fmt.Sprint // 返回字符串不换行 fmt.Sprintln // 返回字符串自动加空格和换行 fmt.Sprintf // 按格式返回字符串 fmt.Fprint // 写入指定 io.Writer不换行 fmt.Fprintln // 写入指定 io.Writer自动换行 fmt.Fprintf // 按格式写入指定 io.Writerfmt 占位符%v // 默认格式 %v // 打印结构体时带字段名 %#v // Go 语法形式 %T // 类型 %% // 百分号 %t // 布尔值 %d // 十进制整数 %b // 二进制整数 %o // 八进制整数 %x // 十六进制小写 %X // 十六进制大写 %c // Unicode 字符 %f // 浮点数 %.2f // 保留 2 位小数 %e // 科学计数法小写 e %E // 科学计数法大写 E %g // 自动选择浮点格式 %s // 字符串 %q // 带引号字符串 %p // 指针地址log 函数log.Print // 打印日志 log.Println // 打印日志并换行 log.Printf // 按格式打印日志 log.Fatal // 打印日志后 os.Exit(1) log.Fatalln // 打印日志后 os.Exit(1) log.Fatalf // 按格式打印日志后 os.Exit(1) log.Panic // 打印日志后 panic log.Panicln // 打印日志后 panic log.Panicf // 按格式打印日志后 panic二十五、总结fmt解决的是“怎么格式化输出”的问题。log解决的是“怎么记录日志”的问题。日常开发中可以简单记住fmt.Println(value) // 简单打印 fmt.Printf(%v\n, structVal) // 调试结构体 fmt.Sprintf(id%d, id) // 生成字符串 fmt.Fprintln(os.Stderr, err) // 输出错误到 stderr log.Println(started) // 打日志 log.Printf(id%d, id) // 格式化日志 log.Fatal(err) // 打印错误并退出程序如果只是学习、调试、命令行输出优先用fmt。如果是服务运行日志、错误记录、程序启动失败退出优先用log。