整数类型
Go语言提供了多种整数类型,包括 int、int8、int16、int32、int64 和 uint、uint8、uint16、uint32、uint64。这些类型的差别在于它们的位数和表示范围。在选择合适的整数类型时,需要考虑数值范围和内存占用。除此之外,还可以使用 uintptr 类型来表示指针或地址。
int 和 uint
在 Go 语言中,int 和 uint 类型可以根据平台位数变化而变化;在 32 位系统中,(u)int 类型的长度就是 (u)int32 的长度,在64 位系统中,就是 (u)int64 的长度。
类型 | 长度 |
---|---|
int8 | -128 ~ 127 |
int16 | -32768 ~ 32767 |
int32 | -2147483648 ~ 2147483647 |
int64 | -9223372036854775808 ~ 9223372036854775807 |
uint8 | 0 ~ 255 |
uint16 | 0 ~ 65535 |
uint32 | 0 ~ 4294967295 |
uint64 | 0 ~ 18446744073709551615 |
Go 语言是强类型语言,(u)int8、(u)int16、(u)int32、(u)int64虽然都是整型,但不同整型的变量不允许直接赋值,需要进行强制类型转换,长度大的整型向下转换时需要考虑溢出问题;而且不同整型的数据无法参与运算,需要转换成同一类型才可运算。
// i 在32位系统中是 2147483647,在64位系统中是 9223372036854775807
var i int = math.MaxInt
// u 在32位系统中是 4294967295,在64位系统中是 18446744073709551615
var u uint = math.MaxUint
var a int8 = math.MaxInt8
var b int16 = math.MaxInt8 + 1
// b 长度过长,此时转换会溢出
a = int8(b)
// 运算时需要转换成同一类型,一般选择向上转换
var c = int16(a) + b
uintptr
uintptr 是 Go 语言中的一个无符号整型,其大小足以容纳指针类型的位模式,包括没有类型信息的指针,常用于进行指针的转换,以及在内存分配、数据传输和指针操作等场景中进行高效的低层次编程。
在标准 Go 语言规范中, uintptr 被定义为一种新的类型,即使在 64 位系统中它的大小也只有 8 个字节。
需要注意的是,uintptr 类型建立了和操作系统的耦合,并不具有可移植性,容易引发安全问题,因此在使用是需要慎重考虑;同时,需要保证任何类型的转换不会导致指针的数据被损坏或访问非法内存地址。
str := "hello world"
// 将 str 转换为指针类型,并转换为 uintptr 类型
ptr := uintptr(unsafe.Pointer(&str))
fmt.Printf("ptr: %x\n", ptr)
// 将 uintptr 转换为指针类型,并通过指针获取原始值
p := (*string)(unsafe.Pointer(ptr))
fmt.Println(*p)
浮点数类型
实数
Go 语言中提供了两种精度的浮点数 float32 和 float64,它们的算数规范由 IEE754 浮点数国际标准定义,该浮点数规范被所有现代 CPU 支持。
类型 | 长度 |
---|---|
float32 | 1.401298464324817e-45 ~ 3.4028234663852886e+38 |
float64 | 5e-324 ~ 1.7976931348623157e+308 |
复数
Go 语言中提供了两种复数类型 complex64 和 complex128;complex64 表示一个由两个 32 位浮点数组成的复数,其实部和虚部都是 float32 类型;complex128 表示一个由两个 64 位浮点数组成的复数,其实部和虚部都是 float64 类型。
可以使用内置函数 complex() 来创建一个复数,complex 函数接收两个参数,分别表示复数的实部和虚部:
// 创建一个complex128类型复数
c1 := complex(1.0, 2.0)
// 创建一个complex64类型复数
c2 := complex(float32(1.0), float32(2.0))
字符类型
byte
byte 是 uint8 的别名,可以存储一个 8 位的无符号整数,一般用来表示 ASCII 字符,只能操作简单的字符,不能处理中文。
rune
rune 是 int32 的别名,可以存储一个 32 位的整数,通常用来表示一个 Unicode 码点,码点无论占多少字节,都可以用一个 rune 来表示。
string
string 用来表示一个字符串,字符串是由多个字符组成的序列,每个字符都可以用 rune 来表示,字符串是不可变的,一旦创建,就不能修改它的内容。字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码
a := "你好,world"
for _, value := range a {
fmt.Print(string(value) + " ")
}
fmt.Println()
b := []byte(a)
for _, value := range b {
fmt.Print(string(value) + " ")
}
fmt.Println()
r := []rune(a)
for _, value := range r {
fmt.Print(string(value) + " ")
}
布尔类型
bool 表示一个布尔值,值为 true 或者 false,零值为 false。在Go 语言中也可以将其他类型的值转换成 bool 类型的值,值为 0 的数、空字符串""、nil 都会转换为 false,其他值转换成 true。
var i int = 0
var s string = ""
var arr []int // 切片类型的零值为 nil
fmt.Println(bool(i)) // 输出:false
fmt.Println(bool(s)) // 输出:false
fmt.Println(bool(arr)) // 输出:false
常量
在 Go 语言中使用 const 关键字来定义常量,定义格式为:const 常量名 类型 = 常量值,常量的值在声明后不能被修改,且必须在编译时就确定下来,不能将函数的返回值赋予常量。定义常量时类型是可以省略的,省略后常量是无类型的,但会根据常量值关联一个默认的数据类型。
const c1 int = 1
const c2 = "A"
// 可以像变量一样批量定义
const(
c3 = 2
c4 = "B"
)
// 常量赋值给变量
var v1 int32 = c1
var v2 float64 = c1
var v3 complex128 = c1
var v4 string = c2
fmt.Printf("v1's type : %T, v2's type : %T, v3's type : %T, v4's type : %T", v1, v2, v3, v4)
Go 语言中没有枚举类型,通常使用一组常量来模拟枚举,可以使用 iota 来简化常量的定义,iota 表示自增的枚举值,从 0 开始,下一个常量的值会增加 1 。
const(
sunday = iota
monday
tuesday
wednesday
thursday
friday
saturday
)
// iota 可以进行运算
const(
b = 1 << (10 * iota)
kb
mb
gb
tb
pb
)