介绍
欢迎各位 Gopher 进入新的篇章。在本节中,我们将学习数值类型。内容包括常用的整数类型、浮点数类型、布尔类型,以及复数和 1.13 版本中引入的字面值语法。
知识点:
- 整数类型
- 浮点数类型
- 布尔类型
- 复数
- 字面值语法
整数
整数可以大致分为两类:无符号整数和有符号整数。有符号整数是使用最广泛的。
无符号意味着它只能表示非负数(0 和正数),而有符号数可以表示负数和非负数。
无符号整数可以分为四种大小:8 位、16 位、32 位和 64 位,分别由 uint8、uint16、uint32 和 uint64 表示。对应的有符号整数是 int8、int16、int32 和 int64。下表显示了每种类型表示的不同范围:
| 类型 | 描述 | 范围 |
|---|---|---|
| uint8 | 8 位无符号整数 | 0 到 255 |
| int8 | 8 位有符号整数 | -128 到 127 |
| uint16 | 16 位无符号整数 | 0 到 65535 |
| int16 | 16 位有符号整数 | -32768 到 32767 |
| uint32 | 32 位无符号整数 | 0 到 4294967295 |
| int32 | 32 位有符号整数 | -2147483648 到 2147483647 |
| uint64 | 64 位无符号整数 | 0 到 18446744073709551615 |
| int64 | 64 位有符号整数 | -9223372036854775808 到 9223372036854775807 |
让我们以 uint8 和 int8 为例。它们都是 8 位的整数,可以表示 256 个值。在无符号整数类型 uint8 中,它可以表示的范围是从 0 到 255,而在有符号整数类型 int8 中,它可以表示的范围是从 -128 到 127。
除了上述 8 种类型之外,还有其他三种特殊的整数类型 uint、int 和 uintptr,其中 uint 和 int 在不同的平台上可能代表不同的范围,而 uintptr 用于存储指针地址。
| 类型 | 范围 |
|---|---|
uint |
在 32 位系统上是 uint32,在 64 位系统上是 uint64 |
int |
在 32 位系统上是 int32,在 64 位系统上是 int64 |
uintptr |
用于存储指针地址的无符号整数类型,主要用于底层编程,例如 unsafe 操作 |
现在,让我们创建一个名为 integer.go 的文件来演示整数的使用:
cd ~/project
touch integer.go
package main
import (
"fmt"
"unsafe"
)
func main() {
// 查看当前环境中 int 的类型
// 声明 a 为 int 类型
var a int
// 使用 unsafe.Sizeof() 输出该类型占用的内存大小
fmt.Printf("The type int in the current environment is %d bits\n", unsafe.Sizeof(a)*8)
var b int8 = 125
// 在 fmt.Printf 中使用 %d 占位符输出整数的值
// 在 fmt.Printf 中使用 %T 占位符输出变量的类型
fmt.Printf("The value of b is %d, and the type is %T\n", b, b)
// 整数运算
// 声明整数 c 和 d,并计算它们的和
c, d := 2, 3
fmt.Printf("c + d = %d\n", c+d)
// 10 - 5
fmt.Printf("10 - 5 = %d\n", 10-5)
// 8 * 10
fmt.Printf("8 * 10 = %d\n", 8*10)
// uintptr 用法示例 - 存储地址
var ptr uintptr
x := 42
// 将指向 x 的指针转换为 uintptr
ptr = uintptr(unsafe.Pointer(&x))
fmt.Printf("The address of x stored in ptr is: %v\n", ptr)
}
执行程序后,我们得到以下输出:
go run integer.go
The type int in the current environment is 64 bits
The value of b is 125, and the type is int8
c + d = 5
10 - 5 = 5
8 * 10 = 80
The address of x stored in ptr is: 824634818784
输出解释:
The type int in the current environment is 64 bits:此行显示运行代码的系统上的int类型是 64 位(或 8 个字节),表明它是int64。unsafe.Sizeof(a)返回变量a的大小(以字节为单位),乘以 8 将其转换为位。这意味着int类型可以容纳更大的整数值。The value of b is 125, and the type is int8:在这里,我们声明了一个int8类型的变量b并为其赋值 125。输出通过显示值和数据类型来确认这一点。c + d = 5、10 - 5 = 5、8 * 10 = 80:这些行展示了基本的整数算术运算:加法、减法和乘法。输出确认了这些计算的正确结果。The address of x stored in ptr is: 824634818784:这演示了如何使用uintptr存储内存地址。我们将指向整数变量x的指针转换为uintptr类型。每次程序运行时,实际地址值都会有所不同。这是一种高级用例,通常在unsafe操作和系统编程中找到。
在此文件中,unsafe.Sizeof() 函数可用于获取当前变量类型占用的字节数。1 字节 (byte) 等于 8 位,因此 unsafe.Sizeof()*8 可以获取该类型占用的位数。从输出中,我们可以看到在线环境是 64 位的。在线环境中 int 的实际类型是 int64。
我们可以在终端中使用以下命令来确定当前的系统架构:
dpkg --print-architecture
amd64
浮点数
浮点数在 Go 中使用 float32 和 float64 两种类型表示带有小数部分的实数。默认的浮点数类型是 float64。
float32 和 float64 表示不同的精度。 float64 的默认精度高于 float32。
IEEE 754 标准是计算机中最广泛使用的浮点数计算标准,现代 CPU 都支持此标准。与其他编程语言一样,Go 也使用 IEEE 754 来存储浮点数。
我们知道计算机中的一个字节可以存储 8 位。 float32 是单精度浮点数,占用 4 个字节,即 32 位。 float64 是双精度浮点数,占用 8 个字节,即 64 位。
在 float32 中,符号位占用 1 位,指数占用 8 位,其余 23 位用于表示尾数。
在 float64 中,符号位也占用 1 位,指数占用 11 位,其余 52 位用于表示尾数。
float32 可以表示的最大值约为科学计数法中的 3.4e+38,最小值是 1.4e-45。 float64 可以表示的最大值约为 1.8e+308,最小值是 4.9e-324。我们可以看到浮点数值的范围可以从非常小到非常大。
我们可以使用常量 math.MaxFloat32 来表示 float32 中的最大值。使用常量 math.MaxFloat64 来表示 float64 中的最大值。
浮点数的表示
输出浮点数时,我们可以使用 fmt 包的 Printf 函数的 %f 占位符。这是一个例子:
cd ~/project
touch float.go
package main
import (
"fmt"
"math"
)
func main() {
// 不使用指数形式输出
fmt.Printf("2.333 without exponential form: %f\n", 2.333)
fmt.Printf("Pi without exponential form: %f\n", math.Pi)
// 使用 %.2f 保留 Pi 的两位小数
fmt.Printf("Pi with two decimal places: %.2f\n", math.Pi)
fmt.Printf("The maximum value of float32: %f\n", math.MaxFloat32)
// 指数形式
fmt.Printf("2.333 in exponential form: %e", 2.333)
}
运行命令,你将看到以下输出。
go run float.go
2.333 without exponential form: 2.333000
Pi without exponential form: 3.141593
Pi with two decimal places: 3.14
The maximum value of float32: 340282346638528859811704183484516925440.000000
2.333 in exponential form: 2.333000e+00
输出解释:
2.333 without exponential form: 2.333000:这显示了使用%f占位符打印的数字2.333。默认情况下,%f占位符显示小数点后 6 位数字,因此2.333变为2.333000。Pi without exponential form: 3.141593:此行打印常量math.Pi的值,它是数学常数 π 的近似值。%f占位符以完整精度显示它。Pi with two decimal places: 3.14:通过使用%.2f,我们告诉fmt.Printf将数字格式化为小数点后两位,结果为3.14。当你只需要输出的特定精度时,这非常有用。The maximum value of float32: 340282346638528859811704183484516925440.000000:这显示了float32可以表示的最大值。请注意,这是一个非常大的数字,并且在使用%f打印时,它将用许多数字表示。2.333 in exponential form: 2.333000e+00:此行显示如何使用%e占位符以指数(科学)计数法表示浮点数。末尾的e+00表示我们将2.333000乘以 10 的 0 次方,即2.333。如果指数是e+02,则该数字将乘以10^2(100),结果为233.3。
布尔类型
bool 类型只有两个可能的值:true 或 false,默认值为 false。它具有以下特点:
- 它不能转换为其他类型,例如将整数转换为布尔值或将布尔值转换为整数。
- 它不能参与算术运算。
布尔类型通常与关系运算符结合使用,例如 =、> 和 <。让我们创建一个名为 bool.go 的文件来看一个演示:
cd ~/project
touch bool.go
package main
import (
"fmt"
)
func main() {
// 在 fmt.Printf 中使用 %t 占位符来表示布尔值
fmt.Printf("Is 3 equal to 2? %t\n", 3 == 2)
fmt.Printf("Is 2 equal to 2? %t\n", 2 == 2)
// 判断 a 和 b 是否相等
a, b := 1, 2
fmt.Printf("a is %d, b is %d\n", a, b)
if a > b {
fmt.Println("a is greater than b")
} else if a == b {
fmt.Println("a is equal to b")
} else {
fmt.Println("b is greater than a")
}
}
运行程序后,我们得到以下输出:
go run bool.go
Is 3 equal to 2? false
Is 2 equal to 2? true
a is 1, b is 2
b is greater than a
输出解释:
Is 3 equal to 2? false:表达式3 == 2的计算结果为false,然后使用%t占位符打印出来。Is 2 equal to 2? true:表达式2 == 2的计算结果为true,然后使用%t占位符打印出来。a is 1, b is 2:此行打印整数变量a和b的赋值。b is greater than a:if-else if-else条件语句的计算结果为a < b,即1 < 2(true),因此执行else语句,导致程序打印“b is greater than a”。
在这个程序中,我们首先在 fmt.Printf 中使用 %t 来表示布尔值,然后使用 if 语句来确定两个值之间的关系。在 fmt.Printf 中,我们可以使用 %d 占位符来表示整数,使用 %f 占位符来表示浮点数,使用 %t 占位符来表示布尔值。
复数
Go 也有内置的复数类型,可以分为 complex64 和 complex128 类型。在 complex64 中,实部和虚部都是 32 位,而在 complex128 中,实部和虚部都是 64 位。我们可以很容易地在 Go 中执行复数运算。
创建一个名为 complex.go 的文件,并输入以下代码:
cd ~/project
touch complex.go
package main
import (
"fmt"
)
func main() {
// 以不同的方式初始化复数
c1 := complex(3, 1)
c2 := 4 + 5i
// 复数运算
c3 := c1 + c2
c4 := c1 * c2
// 使用 real() 函数获取复数的实部,使用 imag() 函数获取复数的虚部
fmt.Printf("The real part of c1 is %v, the imaginary part is %v\n", real(c1), imag(c1))
// fmt.Printf 中的 %v 可以用来表示复数
fmt.Printf("c1 + c2 is %v\n", c3)
fmt.Printf("c1 * c2 is %v\n", c4)
}
运行程序后,我们得到以下输出:
go run complex.go
The real part of c1 is 3, the imaginary part is 1
c1 + c2 is (7+6i)
c1 * c2 is (7+19i)
输出解释:
The real part of c1 is 3, the imaginary part is 1:函数real(c1)提取复数c1的实部,即3,而imag(c1)提取c1的虚部,即1。然后使用%v占位符打印这些值。c1 + c2 is (7+6i):此行显示了复数c1和c2相加的结果。c1定义为3 + 1i,c2定义为4 + 5i。分别添加实部和虚部得到(3 + 4) + (1 + 5)i,即7 + 6i。c1 * c2 is (7+19i):此行显示了复数c1和c2相乘的结果。(3 + 1i) * (4 + 5i)的计算方式为(3*4 - 1*5) + (3*5 + 1*4)i,简化为(12-5) + (15+4)i,最后为7+19i。
在这个程序中,我们演示了如何使用 complex 函数以及 + 和 * 运算符来初始化复数并对其执行运算。 real() 和 imag() 分别用于提取复数的实部和虚部。 fmt.Printf 中的 %v 动词用作通用占位符来显示复数。
字面值语法
在 1.13 版本中,Go 引入了 Numeric Literal Syntax(数字字面值语法)。它定义了数字在不同进制中的表示方式。让我们来看看它的规则。
- 二进制:在整数前添加
0b。例如,0b101等于十进制的5。 - 八进制:在整数前添加
0o或0O。例如,0o11等于十进制的9。 - 十六进制:在整数前添加
0x或0X。例如,0x1b等于十进制的27。 - 使用
_分隔整数中的数字,例如,0b1000_0100_0010_0001等于0b1000010000100001。这可以提高可读性。
让我们详细演示一下:
cd ~/project
touch literals.go
package main
import "fmt"
func main() {
// 二进制,开头添加 0b
var a int = 0b101
fmt.Printf("Binary a is %b, decimal is %d\n", a, a)
// 八进制,开头添加 0o 或 0O
var b int = 0o11
fmt.Printf("Octal b is %o, decimal is %d\n", b, b)
// 十六进制,开头添加 0x 或 0X
var c int = 0x1b
fmt.Printf("Hexadecimal c is %x, decimal is %d\n", c, c)
// 使用分隔符
d := 0b1000_0100_0010_0001
e := 0b1000010000100001
if d == e {
fmt.Println("d is equal to e")
}
}
运行程序后,我们得到以下输出:
go run literals.go
Binary a is 101, decimal is 5
Octal b is 11, decimal is 9
Hexadecimal c is 1b, decimal is 27
d is equal to e
输出解释:
Binary a is 101, decimal is 5:此行显示了0b101的二进制表示形式,即101,其十进制等效值为5。%b占位符显示a的二进制值,而%d显示十进制表示形式。Octal b is 11, decimal is 9:八进制数0o11等于十进制的1*8^1 + 1*8^0 = 8 + 1 = 9。%o占位符显示b的八进制表示形式,而%d显示其十进制值。Hexadecimal c is 1b, decimal is 27:十六进制数0x1b等于十进制的1*16^1 + 11*16^0 = 16 + 11 = 27。%x占位符显示c的十六进制表示形式,而%d显示其十进制值。d is equal to e:这表明二进制字面值0b1000_0100_0010_0001在值上等于0b1000010000100001。下划线仅用于提高可读性,不会更改数字的值。if条件正确地评估为true。
在这个程序中,我们演示了不同进制的声明和输出,以及分隔符的使用。在 fmt.Printf 中,我们使用了不同的占位符来表示不同的进制。例如,%b 表示二进制,%x 表示十六进制。掌握它们将提高编程效率。
总结
让我们回顾一下在本节中学到的内容:
- 整数可以分为有符号整数和无符号整数
- 默认整数类型
int和uint的范围取决于平台 - 浮点数的表示
- 如何使用复数
- 字面值语法的介绍
- 如何使用不同的占位符
在本节中,我们解释并演示了常见的整数类型、浮点类型和布尔类型。我们讨论了它们的大小、范围和用法。我们还介绍了复数和字面常量。数值类型是 Go 程序的基础,学习者务必好好学习。



