Golang中fmt.Printf()方法遇到的问题排查

Golang中fmt.Printf()方法遇到的问题排查

var s = 'a'
fmt.Printf("%T type of s\n",s,"mangalarora")
fmt.Println(s)

输出:

int32 type of s
%!(EXTRA string=mangalarora)97

它应该给出错误,而不是打印出这是额外的字符串输出。

5 回复

感谢您告诉我这一点。我没有阅读文档,只是开始尝试用Go做一些新东西。

而且我认为这应该显示错误,而不是显示额外的字符串。

更多关于Golang中fmt.Printf()方法遇到的问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用 Visual Studio Code 和 Go 插件时至少会给出警告。我猜这来自 go vet。但它不会对额外的参数提出警告。

image

编译时错误还是运行时恐慌?

我更倾向于在编译时出现错误,这样有时会让事情变得更容易。但另一方面,编译器需要特别处理fmt.Printf及其相关函数,而那些使用args...包装这些函数的代码(比如日志记录器)仍然需要在运行时处理这些问题。

然而运行时恐慌会很麻烦……特别是对于动态生成的格式化字符串/参数,它可能导致我的程序崩溃,而我却没有机会对此采取任何措施,或者我不得不在每次使用打印功能时都使用延迟的恐慌处理程序……这也不好玩……

func main() {
    fmt.Println("hello world")
}

谁说过它应该报错?

它的行为符合文档描述:

favicon

fmt package - fmt - Go Packages

格式化错误:

如果为动词提供了无效参数,例如为 %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)
宽度或精度使用非整数值:%!(BADWIDTH) 或 %!(BADPREC)
	Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
	Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
参数索引无效或使用不当:%!(BADINDEX)
	Printf("%*[2]d", 7):       %!d(BADINDEX)
	Printf("%.[2]d", 7):       %!d(BADINDEX)

在Go语言中,fmt.Printf 的行为与预期一致,但代码中存在两个问题导致输出不符合预期。以下是详细解释和修正方法:

  1. 单引号字符类型问题:在Go中,单引号 'a' 表示一个 rune 类型(int32 的别名),而不是字符串。因此,var s = 'a' 声明 s 为 rune 类型,%T 正确输出 int32

  2. fmt.Printf 的格式字符串不匹配fmt.Printf 的第一个参数是格式字符串,其中 %T 是一个格式化动词,用于输出变量的类型。在您的代码中,格式字符串 "%T type of s\n" 只包含一个 %T,但您传递了两个额外参数:s"mangalarora"fmt.Printf 会处理格式字符串中的所有格式化动词,如果额外参数未被使用,它会输出 %!(EXTRA ...) 错误信息。这里,"mangalarora" 是额外参数,因此输出 %!(EXTRA string=mangalarora)

  3. fmt.Println 输出 rune 值fmt.Println(s) 输出 rune 'a' 的整数值 97(因为 rune 是 int32,'a' 的 Unicode 码点是 97)。

如果您期望输出错误,可能是因为误解了 Go 的强类型和 fmt 包的行为。Go 在编译时不会因类型不匹配而报错(除非是语法错误),但 fmt.Printf 在运行时处理格式不匹配时会添加错误信息。

修正后的代码示例: 如果您想输出变量 s 的类型和值,并避免额外参数错误,可以修改如下:

package main

import "fmt"

func main() {
    var s = 'a' // s is of type rune (int32)
    fmt.Printf("%T type of s\n", s) // 只传递一个参数,匹配格式字符串
    fmt.Println(s) // 输出 rune 值 97

    // 如果您想输出字符串,应使用双引号
    var str = "a"
    fmt.Printf("%T type of str\n", str) // 输出: string type of str
    fmt.Println(str) // 输出: a
}

输出:

int32 type of s
97
string type of str
a

如果您希望 fmt.Printf 在格式不匹配时 panic 或返回错误,Go 的 fmt 包不提供此行为;它设计为在运行时处理格式错误并输出信息。对于严格的类型检查,应依赖 Go 的编译时类型系统。

回到顶部