1、Stringer接口
fmt 包中定义的 Stringer
是最普遍的接口之一
type Stringer interface { String() string }
fmt包中有很多方法使用Stringer接口,如下:
package main import ( "fmt" ) type Person3 struct { Name string Age int } func (p Person3) String() string { return fmt.Sprintf("%v (%v years)", p.Name, p.Age) } func main() { a := Person3{"Mujiutian", 89} z := Person3{"Clearlove7", 001} fmt.Println(a, z) }
结果:
Mujiutian (89 years) Clearlove7 (1 years)
进入Sprintf方法中:
上面注释的含义是:根据格式说明符来格式化并返回结果字符串
然后点击进入打印方法doPrintf方法中:
因为这个方法代码行数太多,不能截图,所以把方法代码拷贝过来,之后截图最关键的地方:
func (p *pp) doPrintf(format string, a []interface{}) { end := len(format) argNum := 0 // we process one argument per non-trivial format afterIndex := false // previous item in format was an index like [3]. p.reordered = false formatLoop: for i := 0; i < end; { p.goodArgNum = true lasti := i for i < end && format[i] != '%' { i++ } if i > lasti { p.buf.WriteString(format[lasti:i]) } if i >= end { // done processing format string break } // Process one verb i++ // Do we have flags? p.fmt.clearflags() simpleFormat: for ; i < end; i++ { c := format[i] switch c { case '#': p.fmt.sharp = true case '0': p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left. case '+': p.fmt.plus = true case '-': p.fmt.minus = true p.fmt.zero = false // Do not pad with zeros to the right. case ' ': p.fmt.space = true default: // Fast path for common case of ascii lower case simple verbs // without precision or width or argument indices. if 'a' <= c && c <= 'z' && argNum < len(a) { if c == 'v' { // Go syntax p.fmt.sharpV = p.fmt.sharp p.fmt.sharp = false // Struct-field syntax p.fmt.plusV = p.fmt.plus p.fmt.plus = false } p.printArg(a[argNum], rune(c)) argNum++ i++ continue formatLoop } // Format is more complex than simple flags and a verb or is malformed. break simpleFormat } } // Do we have an explicit argument index? argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a)) // Do we have width? if i < end && format[i] == '*' { i++ p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum) if !p.fmt.widPresent { p.buf.WriteString(badWidthString) } // We have a negative width, so take its value and ensure // that the minus flag is set if p.fmt.wid < 0 { p.fmt.wid = -p.fmt.wid p.fmt.minus = true p.fmt.zero = false // Do not pad with zeros to the right. } afterIndex = false } else { p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end) if afterIndex && p.fmt.widPresent { // "%[3]2d" p.goodArgNum = false } } // Do we have precision? if i+1 < end && format[i] == '.' { i++ if afterIndex { // "%[3].2d" p.goodArgNum = false } argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a)) if i < end && format[i] == '*' { i++ p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum) // Negative precision arguments don't make sense if p.fmt.prec < 0 { p.fmt.prec = 0 p.fmt.precPresent = false } if !p.fmt.precPresent { p.buf.WriteString(badPrecString) } afterIndex = false } else { p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i, end) if !p.fmt.precPresent { p.fmt.prec = 0 p.fmt.precPresent = true } } } if !afterIndex { argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a)) } if i >= end { p.buf.WriteString(noVerbString) break } verb, size := rune(format[i]), 1 if verb >= utf8.RuneSelf { verb, size = utf8.DecodeRuneInString(format[i:]) } i += size switch { case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec. p.buf.WriteByte('%') case !p.goodArgNum: p.badArgNum(verb) case argNum >= len(a): // No argument left over to print for the current verb. p.missingArg(verb) case verb == 'v': // Go syntax p.fmt.sharpV = p.fmt.sharp p.fmt.sharp = false // Struct-field syntax p.fmt.plusV = p.fmt.plus p.fmt.plus = false fallthrough default: p.printArg(a[argNum], verb) argNum++ } } // Check for extra arguments unless the call accessed the arguments // out of order, in which case it's too expensive to detect if they've all // been used and arguably OK if they're not. if !p.reordered && argNum < len(a) { p.fmt.clearflags() p.buf.WriteString(extraString) for i, arg := range a[argNum:] { if i > 0 { p.buf.WriteString(commaSpaceString) } if arg == nil { p.buf.WriteString(nilAngleString) } else { p.buf.WriteString(reflect.TypeOf(arg).String()) p.buf.WriteByte('=') p.printArg(arg, 'v') } } p.buf.WriteByte(')') } }
所以说Sprintf中实现了Stringer接口,其实fmt包下还有很多类似方法实现该接口。其实我们这一小节的目的就是看下底层源码实现Stringer接口了,封装到了fmt包中。
那么接下来,我们说Stringer主要是引入我们将要学习的error接口,这个很重要!
2、error接口
Go 程序使用 error
值来表示错误状态。
type error interface { Error() string }
通常函数会返回一个 error
值,调用的它的代码应当判断这个错误是否等于 nil
来进行错误处理。当返回值等于nil时候,表示执行成功,为true,在java中用true表示,只不过go中用nil表示,否则,为false,就是出现错误!
package main import ( "strconv" "fmt" ) func main() { i, err := strconv.Atoi("42") if err != nil { fmt.Printf("couldn't convert number: %v\n", err) return } fmt.Print(i,err) }
看上面的函数,strconv.Atoi 是数据转换类型,转换成整型,这个函数有没有执行成功取决于err返回值是否为nil,i就是函数执行结果,看上面结果1就是执行成功了。在几乎所有的开发中,都会有这种套路,利用error这个接口,大家可以搜一下,我这里只是基本简单介绍,不过之后的项目中会重新深入讲解的。
3、strconv包使用方法
这个strconv包下由多个go文件,这些go文件中包含了所有的函数和方法。当然还有对应的测试类!
3.1 atob.go
ParseBool 将字符串转换为布尔值
FormatBool 将布尔值转换为字符串 "true" 或 "false"
AppendBool 将布尔值 b 转换为字符串 "true" 或 "false"
3.2 atof.go
ParseFloat 将字符串转换为浮点数
3.3 atoi.go
ErrRange 表示值超出范围
ErrSyntax 表示语法不正确
NumError 记录转换失败
ParseInt 将字符串转换为 int 类型
ParseUint 功能同 ParseInt 一样,只不过返回 uint 类型整数
Atoi 相当于 ParseInt(s, 10, 0)
3.4 itoa.go
FormatUint 将 int 型整数 i 转换为字符串形式
FormatUint 将 uint 型整数 i 转换为字符串形式
Itoa 相当于 FormatInt(i, 10)
AppendInt 将 int 型整数 i 转换为字符串形式,并追加到 dst 的尾部
AppendUint 将 uint 型整数 i 转换为字符串形式,并追加到 dst 的尾部
3.5 ftoa.go
FormatFloat 将浮点数 f 转换为字符串值
AppendFloat 将浮点数 f 转换为字符串值,并将转换结果追加到 dst 的尾部
3.6 quote.go
Quote 将字符串 s 转换为“双引号”引起来的字符串
AppendQuote 将字符串 s 转换为“双引号”引起来的字符串,并将结果追加到 dst 的尾部,返回追加后的 []byte
QuoteToASCII 将字符串 s 转换为“双引号”引起来的 ASCII 字符串,“非 ASCII 字符”和“特殊字符”将被转换为“转义字符”
AppendQuoteToASCII 将字符串 s 转换为“双引号”引起来的 ASCII 字符串,并将结果追加到 dst 的尾部,返回追加后的 []byte
QuoteRune 将 Unicode 字符转换为“单引号”引起来的字符串,“特殊字符”将被转换为“转义字符”
AppendQuoteRune 将 Unicode 字符转换为“单引号”引起来的字符串,并将结果追加到 dst 的尾部,返回追加后的 []byte
QuoteRuneToASCII 将 Unicode 字符转换为“单引号”引起来的 ASCII 字符串,“非 ASCII 字符”和“特殊字符”将被转换为“转义字符”
AppendQuoteRune 将 Unicode 字符转换为“单引号”引起来的 ASCII 字符串,并将结果追加到 dst 的尾部,返回追加后的 []byte
CanBackquote 判断字符串 s 是否可以表示为一个单行的“反引号”字符串,字符串中不能含有控制字符(除了 \t)和“反引号”字符,否则返回 false
关于第三节来源于博客:golang 中strconv包用法
....自己去实践理解吧,到时候用到哪里就查那里就好了。
请发表评论