










上一篇讲了变量,知道了怎么存数据。但存什么类型的数据,Go 有严格的规定
类型决定了两件事:这块内存能存什么样的数据,以及占多少空间
Go 看到 20,判断它是整数,分配一块能存整数的内存。如果你之后想往里存字符串,Go 直接报错,因为类型不匹配
这就是静态类型语言:每个变量的类型在编译阶段就确定了,不能在运行时随意改变
Go 的整数类型分两类:有符号和无符号
有符号整数(可以存负数):
| 类型 | 占用空间 | 范围 |
|---|---|---|
| int8 | 1 字节 | -128 到 127 |
| int16 | 2 字节 | -32768 到 32767 |
| int32 | 4 字节 | -21 亿 到 21 亿 |
| int64 | 8 字节 | 极大 |
| int | 平台相关 | 32 位系统是 int32,64 位是 int64 |
无符号整数(只能存正数和零):
| 类型 | 占用空间 | 范围 |
|---|---|---|
| uint8 | 1 字节 | 0 到 255 |
| uint16 | 2 字节 | 0 到 65535 |
| uint32 | 4 字节 | 0 到 42 亿 |
| uint64 | 8 字节 | 极大 |
| uint | 平台相关 | 同 int |
绝大多数情况直接用 int,不用纠结有的没的。只有在特定场景才考虑具体的类型,比如处理文件字节用 uint8,和 C 语言交互用 int32,需要超大数字用 int64
PRTCL // GO
age := 20 // int,自动推断
var count int64 = 1000000000000 // 明确指定 int64
整数溢出
每种类型有范围上限,超过了会溢出,不报错但结果是错的:
PRTCL // GO
var n int8 = 127
n = n + 1
fmt.Println(n) // 输出 -128,溢出了
int8 最大是 127,加 1 之后超出范围,绕回到 -128。Go 不会自动检测溢出,这是你自己要注意的
数字字面量的写法
除了十进制,Go 还支持其他进制和下划线分隔:
PRTCL // GO
a := 100 // 十进制
b := 0b1100100 // 二进制,前缀 0b
c := 0o144 // 八进制,前缀 0o
d := 0x64 // 十六进制,前缀 0x
big := 1_000_000 // 下划线分隔,纯粹提高可读性,值还是 1000000
浮点数就是带小数点的数字。Go 有两种:
| 类型 | 占用空间 | 精度 |
|---|---|---|
| float32 | 4 字节 | 约 6-7 位有效数字 |
| float64 | 8 字节 | 约 15-16 位有效数字 |
日常用 float64,精度更高,也是 Go 默认推断的浮点类型:
PRTCL // GO
height := 1.75 // 自动推断为 float64
var pi float32 = 3.14159
浮点数的精度问题
浮点数在计算机里是用二进制近似表示的,某些小数无法精确表示:
PRTCL // GO
a := 0.1
b := 0.2
fmt.Println(a + b) // 输出 0.30000000000000004,不是 0.3
这不是 Go 的 bug,是所有编程语言都有的浮点数问题。涉及金额计算时绝对不要用浮点数,应该用整数(比如存分而不是存元)
算钱用浮点,迟早被人扁
科学计数法
PRTCL // GO
a := 1e3 // 1000.0
b := 1.5e-2 // 0.015
布尔类型只有两个值:true 和 false,用于判断条件
PRTCL // GO
isAdmin := true
isLoggedIn := false
布尔值不能和整数互转,这点和 C 语言不一样:
PRTCL // GO
var n int = 1
var b bool = n // ❌ 报错,int 不能赋给 bool
在 C 里 0 是 false、非 0 是 true,但 Go 不允许这样做,必须明确写 true 或 false
字符串是一串字符,用双引号括起来:
PRTCL // GO
name := "Chongxi"
greeting := "Hi, Go!"
字符串是不可变的
一旦创建,字符串的内容不能修改:
PRTCL // GO
name := "Chongxi"
name[0] = 'L' // ❌ 报错,字符串不可修改
要修改只能创建新字符串
字符串拼接
用 + 拼接:
PRTCL // GO
firstName := "Chong"
lastName := "xi"
fullName := firstName + lastName
fmt.Println(fullName) // Chongxi
大量拼接用 strings.Builder,比 + 效率高很多,后面标准库篇会详细讲
多行字符串
用反引号,原样保留所有内容包括换行和缩进:
PRTCL // GO
text := `第一行
第二行
第三行`
fmt.Println(text)
反引号里的内容不处理转义字符,\n 就是两个字符 \ 和 n,不是换行
转义字符
双引号字符串里可以用转义字符:
PRTCL // GO
fmt.Println("第一行\n 第二行") // \n 是换行
fmt.Println("用\"引号\"括起来") // \" 是双引号本身
fmt.Println("路径:C:\\Users") // \\ 是反斜杠
字符串长度
len() 返回字节数,不是字符数:
PRTCL // GO
name := "张三"
fmt.Println(len(name)) // 输出 6,不是 2
因为中文每个字符占 3 个字节(UTF-8 编码),“重熙”是 6 个字节。要得到字符数,后面字符串深入那篇会讲
这两个类型和字符串关系密切,先简单了解:
byte 是 uint8 的别名,表示一个字节,处理 ASCII 字符用:
PRTCL // GO
var b byte = 'A'
fmt.Println(b) // 输出 65,'A' 的 ASCII 码
rune 是 int32 的别名,表示一个 Unicode 字符,处理中文等字符用:
PRTCL // GO
var r rune = ' 张 '
fmt.Println(r) // 输出 24352,' 张 ' 的 Unicode 码
注意字符用单引号,字符串用双引号,两者不一样
字符串和 byte、rune 的深入关系放到下一篇单独讲,内容比较多
Go 内置支持复数,科学计算会用到,日常开发基本不会遇到:
PRTCL // GO
var c complex64 = 1 + 2i
var d complex128 = 3 + 4i
知道有这个东西就行
使用 := 时,Go 按以下规则推断类型:
PRTCL // GO
a := 42 // int
b := 3.14 // float64
c := true // bool
d := "hello" // string
e := 'A' // rune(int32)
整数默认推断为 int,浮点数默认推断为 float64。如果你需要别的类型,必须显式声明:
PRTCL // GO
var a int32 = 42
var b float32 = 3.14
Go 不做隐式类型转换,不同类型之间必须显式转换:
PRTCL // GO
var a int = 42
var b float64 = float64(a) // int 转 float64
var c int = int(b) // float64 转 int,小数部分直接丢弃
float64 转 int 不会四舍五入,直接截断小数部分:
PRTCL // GO
var f float64 = 3.99
var n int = int(f)
fmt.Println(n) // 输出 3,不是 4
整数之间转换要注意范围,大类型转小类型可能溢出:
PRTCL // GO
var a int32 = 1000
var b int8 = int8(a)
fmt.Println(b) // 输出 -24,溢出了
字符串和数字互转不能直接用类型转换,要用 strconv 包,下一篇类型转换会专门讲
常量用 const 声明,值在编译阶段就确定,不能修改:
PRTCL // GO
const Pi = 3.14159
const AppName = "MyApp"
常量可以没有明确类型,这叫无类型常量,它的类型在使用时才确定:
PRTCL // GO
const x = 42 // 无类型整数常量
var a int = x // x 当作 int 用
var b float64 = x // x 当作 float64 用
这种灵活性让常量在赋值时不需要显式转换,比普通变量方便
下一篇单独讲字符串,byte 和 rune 的区别,中文字符怎么处理,以及 strings 包的常用操作
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。