2.1 基本类型
先看一些基础的例子:
变量i属于类型int,在内存中用一个32位字长(word)表示。(32位内存布局方式)
变量j由于做了精确的转换,属于int32类型。尽管i和j有着相同的内存布局,但是它们属于不同的类型:赋值操作 是一种类型错误,必须写成更精确的转换方式:i = int(j)
。
变量f属于float类型,Go语言当前使用32位浮点型值表示(float32)。它与int32很像,但是内部实现不同。
与C相同而与Java不同的是,Go语言让程序员决定何时使用指针。举例来说,这种类型定义:
先来定义一个简单的struct类型,名为Point,表示内存中两个相邻的整数。
Point{10,20}
表示一个已初始化的Point类型。对它进行取地址表示一个指向刚刚分配和初始化的Point类型的指针。前者在内存中是两个词,而后者是一个指向两个词的指针。
结构体的域在内存中是紧挨着排列的。
type Rect2 struct { Min, Max *Point }
Rect1是一个具有两个Point类型属性的结构体,由在一行的两个Point—四个int代表。Rect2是一个具有两个*Point
类型属性的结构体,由两个*Point表示。
使用过C的程序员可能对和*Point
的不同毫不见怪,但用惯Java或Python的程序员们可能就不那么轻松了。Go语言给了程序员基本内存层面的控制,由此提供了诸多能力,如控制给定数据结构集合的总大小、内存分配的次数、内存访问模式以及建立优秀系统的所有要点。
有了前面的准备,我们就可以开始研究更有趣的数据类型了。
(灰色的箭头表示已经实现的但不能直接可见的指针)
(说句题外话,在Java和其他语言里有一个有名的“疑难杂症”:在你分割字符串并保存时,对于源字符串的引用在内存中仍然保存着完整的原始字符串—即使只有一小部分仍被需要,Go也有这个“毛病”。另一方面,我们努力但又失败了的是,让字符串分割操作变得昂贵—包含一次分配和一次复制。在大多数程序中都避免了这么做。)