数据类型对一组相关值进行分类,描述可以对它们执行的操作并定义它们的存储方式。 由于类型可能是一个难以理解的概念,因此在了解它们在 Go 中是如何实现之前,我们将从几个不同的角度来看待它们。
哲学家有时会区分类型和标记。 例如,假设您有一只名叫 Max 的狗。 Max 是标记(特定实例或成员),dog 是类型(一般概念)。“Dog”或“dogness”描述了所有狗共有的一组属性。 尽管过于简单,我们可能会这样推理:所有的狗都有 4 条腿,Max 是一只狗,因此 Max 有 4 条腿。 编程语言中的类型以类似的方式工作:所有字符串都有长度,x 是字符串,因此 x 有长度。
在数学中,我们经常谈论集合。 例如:ℝ(所有实数的集合)或ℕ(所有自然数的集合)。 这些集合的每个成员都与该集合的所有其他成员共享属性。 例如,所有自然数都是结合的:“对于所有自然数 a、b 和 c,a + (b + c) = (a + b) + c 和 a ×(b × c) = (a × b) ×c。” 通过这种方式,集合类似于编程语言中的类型,因为特定类型的所有值共享某些属性。
Go 是一种静态类型的编程语言。 这意味着变量始终具有特定类型并且该类型不能更改。 静态类型起初可能看起来很麻烦。 您将花费大量时间来尝试修复您的程序,以便它最终能够编译。 但是类型可以帮助我们推理我们的程序正在做什么并捕获各种各样的常见错误。
Go 内置集中数据类型,让我们来认识一下吧!
数字类型
Go 有几种不同的类型来表示数字。 通常我们将数字分为两种不同的类型:整数和浮点数。
整型
整数——就像它们的数学对应物——是没有小数部分的数字。 (…, -3, -2, -1,0, 1, …) 与我们用来表示数字的基数为 10 的十进制系统不同,计算机使用基数为 2 的二进制系统。
我们的系统由 10 个不同的数字组成。 一旦我们用尽了可用的数字,我们就通过使用 2 个(然后是 3、4、5 ……)个彼此相邻的数字来表示更大的数字。 例如9后的数字是10,99后的数字是100等等。 计算机也这样做,但它们只有 2 位数字而不是 10。所以计数看起来像这样:0、1、10、11、100、101、110、111 等等。 我们使用的数字系统与一台计算机使用的数字系统之间的另一个区别是所有整数类型都有一个确定的大小。 他们只有一定数量的数字的空间。 所以一个 4 位整数可能看起来像这样:0000, 0001, 0010, 0011, 0100。最终我们用完了空间,大多数计算机只是回到开头。 (这会导致一些非常奇怪的行为)
Go 的整数类型有:uint8、uint16、uint32、uint64、int8、int16、int32 和 int64。
8、16、32 和 64 告诉我们每种类型使用多少位。
uint 表示“无符号整数”,而 int 表示“有符号整数”。
无符号整数只包含正数(或零)。
另外还有两种别名类型:与uint8相同的byte和与int32相同的rune。
字节是计算机上使用的极其常见的度量单位(1 字节 = 8 位,1024 字节 = 1 KB,1024 KB = 1 兆字节,……)因此 Go 的字节数据类型经常用于其他类型的定义。 还有 3 种依赖于机器的整数类型:uint、int 和 uintptr。 它们依赖于机器,因为它们的大小取决于您使用的架构类型。
通常,如果您使用整数,您应该只使用 int 类型。
浮点型
浮点数是包含小数部分(实数)的数字。 (1.234, 123.4, 0.00001234, 12340000) 它们在计算机上的实际表示相当复杂,并不是真正需要知道如何使用它们。 所以现在我们只需要记住以下几点:
- 浮点数是不精确的。 有时无法表示一个数字。 例如,计算 1.01 - 0.99 会得到 0.020000000000000018——一个非常接近我们预期的数字,但并不完全相同。
- 像整数一样,浮点数也有一定的大小(32 位或 64 位)。 使用更大的浮点数会增加它的精度。 (它可以代表多少位数)
- 除了数字之外,还有其他几个可以表示的值:“非数字”(NaN,对于 0/0 之类的东西)以及正无穷大和负无穷大。 (+∞ 和 −∞)
Go 有两种浮点类型:float32 和 float64(通常也分别称为单精度和双精度)以及两种用于表示复数(带虚部的数字)的附加类型:complex64 和 complex128。 通常我们在处理浮点数时应该坚持使用 float64。
例子
package main import ( "fmt" ) func main() { a := 3 b := 4 fmt.Println("1 + 1 =", 1+1) fmt.Println("a + b =", a+b) fmt.Println("1.0 + 1.0 =", 1.0+1.0) }
输出结果为:
1 + 1 = 2 a + b = 7 1.0 + 1.0 = 2
和第一个Hello World程序一样,它包含相同的package main行、相同的 import 行、相同的函数声明并使用相同的 Println 函数。 这次不是打印字符串 Hello World,而是打印字符串 1 + 1 = 后跟表达式 1 + 1 的结果。该表达式由三部分组成:数字文字 1(类型为 int)、 + 运算符(表示加法)和另一个数字文字 1。让我们使用浮点数尝试相同的操作:
请注意,我们使用 .0 来告诉 Go 这是一个浮点数而不是整数。 运行这个程序会给你和以前一样的结果。
除了 + 法 之外还有其他几个操作符:
- 加 +
- 减 -
- 乘 *
- 除 /
- 取余 %
字符串类型
正如我们在前文中看到的,字符串是用于表示文本的具有确定长度的字符序列。 Go 字符串由单个字节组成,通常每个字符一个。 (中文等其他语言的字符用一个以上的字节表示)
可以使用双引号"Hello World"
创建字符串文字。 它们之间的区别在于双引号字符串不能包含换行符,并且它们允许特殊的转义序列。 例如,\n
被换行符替换,\t
被替换为制表符。
对字符串的几种常见操作包括查找字符串的长度:len("Hello World")
,访问字符串中的单个字符:"Hello World"[1]
,以及将两个字符串连接在一起:"Hello " + "World"
. 让我们修改我们之前创建的程序来测试这些:
package main import "fmt" func main() { fmt.Println(len("Hello World")) fmt.Println("Hello World"[1]) fmt.Println("Hello" + "World") }
输出结果为:
11 101 HelloWorld
解释:
- 空格也被认为是一个字符,所以字符串的长度是 11 而不是 10,并且第三行有“Hello”而不是“Hello”。
- 字符串从 0 开始“索引”而不是 1。 [1] 给你第二个元素而不是第一个。 另请注意,当您运行此程序时,您看到的是 101 而不是 e。 这是因为字符由一个字节表示(记住一个字节是一个整数)。考虑索引的一种方法是将其显示为:“Hello World”1。 您可以将其读作“字符串 Hello World sub 1”、“字符串 Hello World at 1”或“字符串 Hello World 的第二个字符”。
- 连接使用与加法相同的符号。Go 编译器根据参数的类型计算出要做什么。 由于 + 的两侧都是字符串,因此编译器假定您的意思是连接而不是加法。 (加法对字符串没有意义)
布尔型
布尔值(以 George Boole 命名)是一种特殊的 1 位整数类型,用于表示真假(或开和关)。 三个逻辑运算符与布尔值一起使用:
- && - and
- || - or
- ! - not
常见的真值表如下:
表达式 | 结果 |
true && true |
true |
true && false |
false |
false && true |
false |
false && false |
false |
true || true |
true |
true || false |
true |
false || true |
true |
flase || false |
false |
! true |
false |
! false |
true |
代码如下:
package main import "fmt" func main() { fmt.Println(true && true) fmt.Println(true && false) fmt.Println(true || true) fmt.Println(true || false) fmt.Println(!true) }
true false true true false