类型声明
Go语言的类型声明有两种形式:
别名类型声明
type (
别名 = 类型名
{别名 = 类型名}
)
别名与原始类型完全等价。
定义类型声明
type (
新类型名 类型名
{新类型名 类型名}
)
新类型与原始类型是不同的两个类型。
不论哪种形式,如果只声明一个类型,可以把圆括号省略。
两种形式的区别我们可以通过以下程序片断来认识:
type (
INT = int // INT是int的别名
BOOL bool // BOOL的基类型是bool,但它是个新的类型
)
var i INT = 20
var j int = 40
j = i // OK,INT与int是相同类型
i = j // OK,int与INT是相同类型
var b BOOL = true
var c bool = false
c = b // 错误,cannot use c (type bool) as type BOOL in assigment
b = c // 错误,cannot use b (type BOOL) as type bool in assigment
基本类型
数值类型
预定义的架构无关的数值类型有:
uint8 所有无符号8位整数 (0 to 255)
uint16 所有无符号16位整数(0 to 65535)
uint32 所有无符号32位整数(0 to 4294967295)
uint64 所有无符号64位整数 (0 to 18446744073709551615)
int8 所有有符号8位整数 (-128 to 127)
int16 所有有符号16位整数 (-32768 to 32767)
int32 所有有符号32位整数 (-2147483648 to 2147483647)
int64 所有有符号64位整数 (-9223372036854775808 to 9223372036854775807)
float32 所有IEEE-754 32位浮点数
float64 所有IEEE-754 64位浮点数
complex64 所有具有float32 实数和虚数部分的复数
complex128 所有具有float64 实数和虚数部分的复数
别名:
byte uint8的别名
rune int32的别名
还有一些预定义的大小与平台相关的数值类型:
uint 可能是 32位或 64 位
int 大小与uint一样
uintptr 足够存放指针值的无符号整数
除了type和rune两个类型是别名外,所有的数值类型都是定义类型。正如前面介绍过的,所有的定义类型都是不同的,所以在一个表示达中,数值类型之间的混合操作需要进行类型转换。
rune 类型
这里特别要把rune类型拿出来说明一下。rune类型是int32类型的别名,用于rune来表示Unicode码点。有三种表示形式,一种是常见的单个字符:
'a' // 0x61
'ä' // 0xe4 / utf-8编码 0xc3 0xa4
'我' // 0x6211 / utf-8编码 0xe6 0x88 0x91
第二种是单引号内的单个转义字符:
\a U+0007 蜂鸣
\b U+0008 退格
\f U+000C 馈页
\n U+000A 新行
\r U+000D 硬回车
\t U+0009 横向制表
\v U+000b 纵向制表
\\ U+005c 反斜杠
\' U+0027 单引号
第三种是单引号内值转义:
将指定的值转成rune值,虽然最终的结果都是int32,但是根据位数的不同,存在取值范围的限制。
\xXX X表示十六进制数字(只能是两位)
\uXXXX X表示十六进制数字(只能是四位)
\UXXXXXXXX X表示十六进制数字(只能是八位)
\XXX X表示八进制数字(只能是三位)
由于run表示的是Unicode码点,所以可以将string转换成rune切片来计算字符串的长度:
s := "Go语言学习"
len(s) // 14, s共占用14个字节(utf-8编码)
len([]rune(s)) //6,s共有6个字符
布林类型
预定义的布林类型的类型名为bool,它是定义类型。其真值是true或false两个预定义无类型常量之一。
字符串类型
预定义的字符串类型的类型名为string,它是定义类型。
字符串类型可以表示字符串值,而一个字符串值是一系列字节(可为空)。string类型是不可修改的。
字符串类型的字节长度可以由内置函数len取得。可以用下标的方式访问字符串内的字节,但不能使用&s[i]的方式来取元素的地址。
字符串有两种表示形式,原始字符串:
`字符序列`
在两个反引号中间的字符序列就是字符串,除了反引号字符本身外,所有的字符都可以出现在反引号中间,字符不能转义。
解析字符串:
“字符序列”
在两个双引号中间的字符序列都属于字符串,除了新行符及未转义的双引号外,所有的字符都可以出现在双引号中间,特殊字符需要用反斜杠转义:
\a U+0007 蜂鸣
\b U+0008 退格
\f U+000C 馈页
\n U+000A 新行
\r U+000D 硬回车
\t U+0009 横向制表
\v U+000b 纵向制表
\\ U+005c 反斜杠
\" U+0022 双引号
数组类型
数组是具有确定数量的同一类型顺序元素的集合。它是定义类型。数组的长度是数组类型的一部分,可以用内置函数len取得。数组的元素可以用下标来访问和寻址。数组类型的语法形式:
[长度] 元素的类型名
其中长度可以是int常量或结果为int型常量的表达式。
[32]byte
const N=1
[2*N] struct { x, y int32 }
[1000]*float64
构造数组类型值的时候可以这样写:
ary := [...]int{1,2,3} // 构造一个类型为[3]int的数组
数组总是一维的,但是可以嵌套:
[2][3][4]float64 // 就是 [2]([3]([4]float64))
len([2][3][4]float64{}) // 2,只取第一维的长度
切片类型
切片就是以一个数组以底层数据,截取其中一个连续片断。切片类型代表了其元素类型所有数组的切片。切片的语法形式如下:
[] 元素的类型名
与数组一样,切片也有长度,可以用内置函数len来取得。
切片的元素可以通过下标来访问和寻址,切片元素的下标与其代表的底层数组元素的下标有可能不一样。
对于同一数组的不同切片,它们与数组共享相同的存储。相对的,相同类型的不同数组,们的存储是不同的。
底层数组是有可能超过切片的结尾的,从切片头所代表的数组元素到数组未尾的元素的个数称为切片的容量,可以用内置函数cap来取得。因此从切片中“切出”的新的切片其长度最长可以是这个容量的值:
ary := [...]int{0,1,2,3,4,5,6,7,8,9} // 创建一个长度为10的int数组
s1 := ary[2:3] // 从ary[2]创建一个长度为1(即3-2)的切片,此时 s1 =[2] len(s1)=1 cap(s1)=8
s2 := s1[1:cap(s1)] // 从s1[1]创建一个长度为7的切片,即s2=[3 4 5 6 7 8 9]
切片还可以通过内置函数make来创建,这会给切片分配一个底层数组:
make(切片类型, 长度, 容量)
长度不能大于容量,如果容量缺省,则切片的容量与长度相同。使用make实际上相当于创建一个数组,并在它上面创建了一个切片:
make([]int, 50, 100)
new([100]int)[:50] // 这两个是等价的
结构体类型
结构体由一系列称为字段的元素组成,每个字段都有各自的名字和类型,字段名必须唯一。结构体的语法:
struct {
字段列表
}
我们用实例来演示结构体字段:
type sex byte
struct {
name string // 字段名 name,字段类型 string
sex // 嵌入字段 sex,字段类型 sex
weight, height float32 // 显式字段名weigth和height,字段类型都是float32
_ float32 // 空标识符,填充
_ int // 空标识符可以多个
*int // 嵌入字段 int,字段类型*int
**string // 错误,不能把指针的指针类型用作隐式字段名
name int // 错误,字段重名
}
对于一个结构体x,如果它的一个嵌入字段T拥有方法(或字段)f,并且x.f能够唯一标识到这个方法(或字段),则称这个方法(或字段)f为提升的。提升的方法(或字段)可以像x的成员方法(或字段)一样使用,但在构造结构体的时候除外: