Go 有几种内建的数字类型 Numeric types,“整数或浮点值的集合。”里面包含了体系结构无关(architecture-independent)的类型,如:uint8(8bit,无符号整型)、int16(16bit,有符号整型) 以及 complex128(128bit,复数)。有趣的是,Go 规范里还包含了体系结构相关(architecture-dependent)类型:

* uint

* int

* uintptr

这些类型需要多位bit呢?规范里说int和uint的大小相同,"32bit或64bit"。uintptr是"一个足够大的无符号整数,用于存储指针值的未解释位(uninterpreted bits)。"

到目前为止,我见过的这三种类型中最常见的是int。如果你的知道你的程序只使用非负数,那么可以使用uint代替。使用uintptr最常见的是你导入 unsafe的时候,这听起来很安全。

实例

如果这些类型依赖于体系结构,那么我们如何判断一个int对于我们关心的体系结构有多大呢?一种方法是通过编译器源代码,将目标体系结构映射到其相应的位大小。但是,至少有两种解决方案比这更好:

* Use architecture-independent types 如果你需要确切知道 int在程序中使用了多少位,请不要依赖于编译器的奇思妙想--使用其中一种预定义类型(如:int64)!这表示,作者意图是想告诉你,这是个具有特定大小的变量(大小包含在类型的名称里),从而提高可读性并在以后读取代码时节省心理资源。

* 写个程序告诉你 标准库strconv中包含了一个帮助程序,可以让你知道int的大小 strconv.IntSize,“是int或uint值的位大小”,你可以在程序中,像这样 使用:

// This program prints the number of bits in an int.

package main

import (

"fmt"

"strconv"

)

func main() {

fmt.Println(strconv.IntSize)

}

在32位体系结构上,打印32。64位体系结构上,打印64。检验下 使用,在你的电脑上,或者32位的docker镜像(e.g.`i686/ubuntu`)

位魔法

你可以在 http://wirecellar.com/5W1n 看到 strconv.IntSize的定义

const intSize = 32 << (^uint(0) >> 63)

// IntSize is the size in bits of an int or uint value.

const IntSize = intSize

让我们将其分解为单独的 按位运算,看看它是如何工作的。

* 无符号整数用2进制表示,每个位对应于2的增加幂。如:`1101`等于`1*2 + 1*2 + 0*2 + 1*2 = 8 + 4 + 0 + 1`, 或者`13`


* ^运算符执行按位补码。 ^从1到0和0到1翻转位,如:3的无符号位`^(101) = 010`。

* `uint(0)`使用 类型转换来获取类型为`uint`的0值。

* `>>` 是右移操作符,右移将所有位向右移动,从右侧删除位并在左侧插入零。如:3的无符号位 `101 >> 2 = 001`。

* `<<` 是左移操作符,跟 `>>` 类似,但是反方向。如:`101 << 2 = 100`。

以下是上述strconv.IntSize表达式中所有这些运算符的使用方法:


换句话说:

1. 从0开始

2. ^将所有位翻转为1

3. 右移(>>)63,64位数字为1和32位数字变为0。

4. 32 左移(<<)

5. 32位体系结构得到32,64位体系结构得到64

Go中int的未来

任意精度整数都可能导致问题。比如:

* 如果你的应用程序在32位计算机上运行,但是你假设int有64位,该怎么办?你的变量可能会偷偷地溢出了。

* 将大值转换为int会变的很困难。你必须要小心,不要超过界限。

在Go2中, Rob Pike 提议将int和uint 变成任意精度,根据需要增长以适应任意值。

strconv.IntSize的结果依赖于实际的int和uint是32位还是64位

如果int是32位或128位,该怎么能修改它呢?

你知道有什么其他技巧来学习一个int在Go中的大小吗?请在评论中告诉我。

这篇博文受 Franziska Hinkelmann的 V8 Internals: How Small is a ‘Small Integer?’ 的启发,我强烈建议您阅读它以了解有关整数如何在JavaScript中运行的更多信息。