从源码学习 Go 标准库(二):fmt - print(3)
2024-01-09 01:18:22
您好,我是喜欢研究编程语言实现的code秘密,很高兴能在这里分享我的研究成果。今天,我将继续带着大家一起阅读Go语言的源码,解读fmt包中print函数的实现。我们将在上篇文章的基础上,继续分析doPrintf函数中宽度和精度的处理部分,并深入研究函数调用的更深层细节。
在上一篇文章中,我们已经梳理了不同打印函数的输出格式,复习了显式参数索引的相关知识,并且分析了函数调用过程中的前两层。现在,我们继续往下看。
// skip leading spaces
for ; i < argIndex && strings.HasPrefix(flags, " "); i++ {
}
// 确定 width,设置 flag
if i < argIndex && flags[i] == '-' {
flag -= FlagLeft
i++
}
// 确定 width
if i < argIndex && flags[i] >= '0' && flags[i] <= '9' {
width = atoi(flags[i:])
if width == 0 {
width = -1
}
i += len(strconv.Itoa(width))
}
// 确定 precision
if i < argIndex && flags[i] == '.' {
i++
prec1 := 0
if i < argIndex && flags[i] >= '0' && flags[i] <= '9' {
prec1 = atoi(flags[i:])
i += len(strconv.Itoa(prec1))
} else {
prec1 = -1
}
prec = strconv.Itoa(prec1)
}
在这一段代码中,我们首先跳过任何位于参数索引前面的空格,然后检查下一个字符是否是减号(-
)。如果是,我们就将flag
减去FlagLeft
,并跳过下一个字符。接下来,我们检查下一个字符是否是数字,如果是,我们就解析它作为宽度(width),并跳过相应的字符。
接下来,我们检查下一个字符是否是句点(.
)。如果是,我们就跳过下一个字符,然后检查下一个字符是否是数字。如果是,我们就解析它作为精度(precision),并跳过相应的字符。如果不是,我们就将精度设置为-1。
现在,我们已经解析了宽度和精度,接下来我们就可以调用fmtFprintf
函数来格式化我们的参数。
fmtFprintf(w, format, val...)
fmtFprintf
函数与fmt.Fprintf
函数非常相似,但是它允许我们直接传入要格式化的参数,而不是使用fmt.Sprint
函数将其转换为字符串。
在调用fmtFprintf
函数之后,我们就完成了对参数的格式化,接下来我们就需要将格式化的结果输出到目标位置。
if fill == '0' && flag&FlagLeft == 0 {
padchar := ' '
if flag&FlagSharp != 0 {
padchar = '0'
}
for i = width - len(s); i > 0; i-- {
w.WriteByte(padchar)
}
}
w.WriteString(s)
if fill == '-' || flag&FlagLeft != 0 {
for i = width - len(s); i > 0; i-- {
w.WriteByte(' ')
}
}
在这一段代码中,我们首先检查填充字符(fill
)和标志(flag
)是否满足某些条件。如果满足,我们就使用WriteByte
函数将填充字符输出到目标位置。接下来,我们使用WriteString
函数将格式化的字符串输出到目标位置。最后,如果填充字符或标志满足某些条件,我们就使用WriteByte
函数将空格输出到目标位置。
以上就是对Go语言源码中fmt
包的print
函数的分析。希望这篇文章对您有所帮助。