Golang 进阶:strconv -- 字符串和基本数据类型之间转换

strconv 包转换错误处理

先来看一下 strconv 中是如何对错误进行处理的:
在 strconv 的包中包含着两种 error 类型的变量:ErrRangeErrSyntax
ErrRange 表示的是值超过了类型能表示的最大范围
ErrSyntax 表示的是语法错误
而我们返回的错误并不是一个简单的 Error,返回的错误是一个 NumError 的类型的 error 对象。具体结构定义如下:

// A NumError records a failed conversion.
type NumError struct {
 Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
 Num  string // the input
 Err  error  // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
}

而且,strconv 本身也实现了一个 Error() 的接口:

func (e *NumError) Error() string {
	return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
}

同时,为了满足我们前面所提到的两种错误类型,在 strconv 包中还特意定义了两个用于构造这两种错误类型的函数:

func syntaxError(fn, str string) *NumError {
    return &NumError{fn, str, ErrSyntax}
}
func rangeError(fn, str string) *NumError {
    return &NumError{fn, str, ErrRange}
}

从函数的定义中我们可以看出,这是用来对两种函数做定义初始化的,相当于是两个构造函数。在我们遇到前面所提到的两种错误时,我们就可以用这两个函数来构造相应的 error 对象。

字符串和整型之间的转换

字符串转为整型

关于将字符串转为整型的问题上,strconv 包中提供了三种方法:

func ParseInt(s string, base int, bitSize int) (i int64, err error)
func ParseUint(s string, base int, bitSize int) (n uint64, err error)
func Atoi(s string) (i int, err error)

我们最常用的应该就是 Atoi() 了,而这个函数时 ParseInt 的一个简易版。在 Atoi 函数的内部,我们可以看到:

// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
func Atoi(s string) (int, error) {
    ...
    // Slow path for invalid or big integers.
	  i64, err := ParseInt(s, 10, 0)
}

也就是说 Atoi 相当于是 ParseInt(s, 10, 0)。所以我们来着重看一下 ParseInt 函数。
ParseInt 函数中有两个参数,其中参数 base 代表字符串将按照给定的 进制 进行转化。
一般的,base 的取值为 2~36,如果 base 的值为 0,则会根据字符串的前缀来确定 base 的值:0x 表示 16 进制; 0 表示 8 进制;否则就是 10 进制。
而第三个参数 bitSize 则表示的是整数的具体类型。取值 0、8、16、32 和 64 分别代表 int、int8、int16、int32 和 int64。
在 bitSize=0 时,这是一种比较特殊的情况,而对于这种情况,在源码中,是对 0 进行了这样转换:

const intSize = 32 << uint(^uint(0)>>63)
const IntSize = intSize // number of bits in int, uint (32 or 64)

ParseInt 函数是有返回值的,而且返回值有两个,n 和 err,err 我们很好理解,而且返回的两种错误值我们在前面也已经提及,我们要说一下,n 返回的是什么内容,在这里,n 返回的是 bitSize 能够表示的最大或最小值
另外,ParseInt 返回的是 int64,这是为了能够容纳所有的整型,在实际使用中,可以根据传递的 bitSize,然后将结果转为实际需要的类型。

整型转为字符串

除了将字符串转化为整型的需求,将整型转换为字符串也是同样需要的。我们同样还是需要借助 strconv 这个包:

func FormatUint(i uint64, base int) string    // 无符号整型转字符串
func FormatInt(i int64, base int) string    // 有符号整型转字符串
func Itoa(i int) string

其中,Itoa 内部直接调用 FormatInt(i, 10) 实现的。base 参数可以取 2~36(0-9,a-z)。
而具体实现的方法则是将整数每一位数字对应到相应的字符,存入字符数组中,最后字符数组转为字符串即为结果。在具体实现时,当 base 是 2 的幂次方时,有优化处理(移位和掩码);十进制也做了优化。
除此之外,在库中还提供了两个函数:AppendInt 和 AppendUint。这两个函数不是将整数转为字符串,而是将整数转为字符数组 append 到目标字符数组中。

字符串和布尔值之间的转换

Go中字符串和布尔值之间的转换比较简单,主要有三个函数:

// 接受 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False 等字符串;
// 其他形式的字符串会返回错误
func ParseBool(str string) (value bool, err error)
// 直接返回 "true" 或 "false"
func FormatBool(b bool) string
// 将 "true" 或 "false" append 到 dst 中
// 这里用了一个 append 函数对于字符串的特殊形式:append(dst, "true"...)
func AppendBool(dst []byte, b bool)

字符串和浮点数之间的转换

这里同样涉及到三个函数:

func ParseFloat(s string, bitSize int) (f float64, err error)
func FormatFloat(f float64, fmt byte, prec, bitSize int) string
func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int)

函数的命名和作用跟上面讲解的其他类型一致。
但由于浮点数有精度的问题,精度不一样,ParseFloat 和 FormatFloat 可能达不到互逆的效果。如:

s := strconv.FormatFloat(1234.5678, 'g', 6, 64)
strconv.ParseFloat(s, 64)

特别地(不区分大小写),+inf/inf,+infinity/infinity,-inf/-infinity 和 nan 通过 ParseFloat 转换分别返回对应的值(在 math 包中定义)。

其他导出的函数

如果我们想要数据依据带有双引号的字符串该怎么做呢?
简单一点的方法就是:

fmt.Println(`This is "a"`)

这样就可以得到我们希望得到的内容。
但其实,在 strconv 的包中,还提供着 Quote() 这样的一个函数,
就比如上面这句话,我们就可以通过这个函数将他按照我们希望的格式输出出来:

fmt.Println("This is", strconv.Quote("a"))

你可能感兴趣的:(技术)