#### 问题来源
刚才查资料的时候,看到帖子 https://studygolang.com/articles/2231
根据帖子的表述,我理解为
```golang
i, err := strconv.ParseInt("123", 10, 32) 的意思是 (字符串123 , 十进制,int32)
i 返回的结果为 123 的类型 是 int32
如果代码改成下面这样的
i, err := strconv.ParseInt("123", 10, 64) 的意思是 (字符串123 , 十进制,int64)
i 返回的结果为 123 的类型 是 int64
```
<br/>
我写了一个例子感觉结果不符合预期
```golang
package main
import (
"fmt"
"github.com/imroc/biu"
"reflect"
"strconv"
)
func main() {
a := "1"
aNumber, err := strconv.ParseInt(a, 10, 64) // string 转 int64
if err != nil {
panic(err)
}
b := "1"
bNumber, err := strconv.ParseInt(b, 10, 32) // string 转 int32
if err != nil {
panic(err)
}
c := "1"
cNumber, err := strconv.ParseInt(c, 10, 8) // string 转 int8
if err != nil {
panic(err)
}
fmt.Printf("a %s %s 转整型 结果为: %s %d \n", reflect.TypeOf(a), a, reflect.TypeOf(aNumber), aNumber)
fmt.Printf("b %s %s 转整型 结果为: %s %d \n", reflect.TypeOf(b), b, reflect.TypeOf(bNumber), bNumber)
fmt.Printf("c %s %s 转整型 结果为: %s %d \n", reflect.TypeOf(c), c, reflect.TypeOf(cNumber), cNumber)
fmt.Println("a 内存地址 ", &a)
fmt.Println("b 内存地址 ", &b)
fmt.Println("c 内存地址 ", &c)
fmt.Println("a bit细节 ", biu.ToBinaryString(aNumber))
fmt.Println("b bit细节 ", biu.ToBinaryString(bNumber))
fmt.Println("c bit细节 ", biu.ToBinaryString(cNumber))
}
```
<br/>
**运行结果**
```golang
a string 1 转整型 结果为: int64 1
b string 1 转整型 结果为: int64 1
c string 1 转整型 结果为: int64 1
a 内存地址 0xc000010280
b 内存地址 0xc000010290
c 内存地址 0xc0000102a0
a bit细节 [00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001]
b bit细节 [00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001]
c bit细节 [00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001]
```
<br/>
**结果好像不符合预期?不管是64,32,还是8,返回的结果都是int64<br/>
我有点困惑,不知道是我理解错误?还是我测试的代码有问题?<br/>
为此我找到函数源码,函数源码如下
**
<br/>
```golang
// ParseInt interprets a string s in the given base (0, 2 to 36) and
// bit size (0 to 64) and returns the corresponding value i.
//
// If base == 0, the base is implied by the string's prefix:
// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x",
// and base 10 otherwise. Also, for base == 0 only, underscore
// characters are permitted per the Go integer literal syntax.
// If base is below 0, is 1, or is above 36, an error is returned.
//
// The bitSize argument specifies the integer type
// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
// correspond to int, int8, int16, int32, and int64.
// If bitSize is below 0 or above 64, an error is returned.
//
// The errors that ParseInt returns have concrete type *NumError
// and include err.Num = s. If s is empty or contains invalid
// digits, err.Err = ErrSyntax and the returned value is 0;
// if the value corresponding to s cannot be represented by a
// signed integer of the given size, err.Err = ErrRange and the
// returned value is the maximum magnitude integer of the
// appropriate bitSize and sign.
func ParseInt(s string, base int, bitSize int) (i int64, err error) {
const fnParseInt = "ParseInt"
if s == "" {
return 0, syntaxError(fnParseInt, s)
}
// Pick off leading sign.
s0 := s
neg := false
if s[0] == '+' {
s = s[1:]
} else if s[0] == '-' {
neg = true
s = s[1:]
}
// Convert unsigned and check range.
var un uint64
un, err = ParseUint(s, base, bitSize)
if err != nil && err.(*NumError).Err != ErrRange {
err.(*NumError).Func = fnParseInt
err.(*NumError).Num = s0
return 0, err
}
if bitSize == 0 {
bitSize = int(IntSize)
}
cutoff := uint64(1 << uint(bitSize-1))
if !neg && un >= cutoff {
return int64(cutoff - 1), rangeError(fnParseInt, s0)
}
if neg && un > cutoff {
return -int64(cutoff), rangeError(fnParseInt, s0)
}
n := int64(un)
if neg {
n = -n
}
return n, nil
}
```
<br/>
原谅我不太好的英文,我用谷歌翻译了一下这个函数的注释,下面是翻译结果
<br/>
>ParseInt解析给定基数(0、2到36)和位大小(0到64)中的字符串s,并返回相应的值i。
>如果base == 0,则该字符串的前缀隐含基数:“ 0b”的基数为2,“ 0”或“ 0o”的基数为8,“ 0x”的基数为16,否则为10。此外,仅对于base == 0,根据Go整数文字语法允许使用下划线字符。如果base小于0,小于1或大于36,则返回错误。
>bitSize参数指定结果必须适合的整数类型。位大小0、8、16、32和64分别对应于int,int8,int16,int32和int64。如果bitSize小于0或大于64,则返回错误。
>ParseInt返回的错误的具体类型为* NumError,其中包括err.Num = s。如果s为空或包含无效数字,则err.Err = ErrSyntax,返回值为0;否则,返回0。如果与s对应的值不能用给定大小的有符号整数表示,则err.Err = ErrRange,并且返回的值是适当的bitSize和sign的最大大小整数。
里面对于第三个参数是这样解释的
bitSize参数指定结果必须适合的整数类型。位大小0、8、16、32和64分别对应于int,int8,int16,int32和int64。如果bitSize小于0或大于64,则返回错误。
好像与帖子的 参数3 返回结果的bit大小 也就是int8 int16 int32 int64有异曲同工之妙
但是根据我的例子,**<span style="color:red">我不太明白strconv.ParseInt的第三个参数的作用是什么?</span>**<br/>
不管是64,还是32,还是8,返回的结果都是int64
**我的go环境**
```bash
$ go version
go version go1.13 linux/amd64
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/**/.cache/go-build"
GOENV="/**/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/**/study/languages/go/golangWork"
GOPRIVATE=""
GOPROXY="https://goproxy.io,direct"
GOROOT="/**/opt/softTarget/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/**/opt/softTarget/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build285609338=/tmp/go-build -gno-record-gcc-switches"
```
<br/>
最后解释一下为啥没在原帖下面回复,主要是内容有点多,而且原帖2015-01-22发布的,新帖发布之后,我会在原帖回复一个新帖的链接
通过观察func ParseInt源码不难发现,bitsize的用意在于限制生成的int类型的位数,如果类型转换生成的int位数超过了规定的bitszie,则panic。您可以尝试把这一行的c的值改为128,他将panic报错,如果您将其改为127,那么将会正常执行。
```
c := "128"
cNumber, err := strconv.ParseInt(c, 10, 8) // panic
c := "127"
cNumber, err := strconv.ParseInt(c, 10, 8) // ok
```
#1
更多评论
感谢,根据你的提示,大概明白了第三个参数的意义
我新写了个例子,来验证了这个
```golang
package main
import (
"fmt"
"github.com/imroc/biu"
"reflect"
"strconv"
)
func main() {
d := "127"
dNumber, err := strconv.ParseInt(d, 10, 8) // ok
if err != nil {
fmt.Println("dNumber 错误 %v", err)
}
e := "128"
eNumber, err := strconv.ParseInt(e, 10, 8) // panic
if err != nil {
fmt.Println("eNumber 错误 %v", err)
}
f := "300"
fNumber, err := strconv.ParseInt(f, 10, 8) // panic
if err != nil {
fmt.Println("fNumber 错误 %v", err)
}
g := int(128)
gNumber := int8(g)
h := int(300)
hNumber := int8(h)
fmt.Printf("d %d 类型 %s \n", dNumber, reflect.TypeOf(dNumber))
fmt.Printf("e %d 类型 %s \n", eNumber, reflect.TypeOf(eNumber))
fmt.Printf("f %d 类型 %s \n", fNumber, reflect.TypeOf(fNumber))
fmt.Printf("g %d 类型 %s \n", gNumber, reflect.TypeOf(gNumber))
fmt.Printf("h %d 类型 %s \n\n", hNumber, reflect.TypeOf(hNumber))
fmt.Println("d bit细节 ", dNumber, biu.ToBinaryString(dNumber))
fmt.Println("e bit细节 ", eNumber, biu.ToBinaryString(eNumber))
fmt.Println("f bit细节 ", fNumber, biu.ToBinaryString(fNumber))
fmt.Println("g bit细节 ", gNumber, biu.ToBinaryString(gNumber))
fmt.Println("h bit细节 ", hNumber, biu.ToBinaryString(hNumber))
}
```
#### 运行结果
```golang
eNumber 错误 %v strconv.ParseInt: parsing "128": value out of range
fNumber 错误 %v strconv.ParseInt: parsing "300": value out of range
d 127 类型 int64
e 127 类型 int64
f 127 类型 int64
g -128 类型 int8
h 44 类型 int8
d bit细节 127 [00000000 00000000 00000000 00000000 00000000 00000000 00000000 01111111]
e bit细节 127 [00000000 00000000 00000000 00000000 00000000 00000000 00000000 01111111]
f bit细节 127 [00000000 00000000 00000000 00000000 00000000 00000000 00000000 01111111]
g bit细节 -128 10000000
h bit细节 44 00101100
```
**第三个参数根据int类型位数,限制了最大的数值,超过则返回错误且数值等于最大数值**
同时需要注意整型之间的转换,int大数值高位往低位转的时候,可能不符合预期结果,需要特别注意
比如例子中的 int(300) 转成int8时,结果为 44
#2