要点
变量有确定类型;没有显式初值也有零值。:= 是声明,= 是给已有变量赋值,这个区别决定能否在同一作用域再次使用。
变量声明和初始化
1. 基本变量声明
Go 提供多种变量声明方式:
方式1: 标准声明
// var 变量名 类型 = 值
var name string = "张三"
var age int = 25
var height float64 = 175.5
var isStudent bool = true
方式2: 类型推断
// var 变量名 = 值 (编译器自动推断类型)
var name = "张三" // 自动推断为string
var age = 25 // 自动推断为int
var height = 175.5 // 自动推断为float64
var isStudent = true // 自动推断为bool
方式3: 短变量声明(函数内)
// 变量名 := 值 (只能在函数内使用)
name := "李四"
age := 30
height := 180.0
isStudent := false
2. 批量声明
// 方式1: 批量标准声明
var (
username string = "admin"
password string = "123456"
loginCount int = 0
isActive bool = true
)
// 方式2: 多变量声明
var x, y, z int = 1, 2, 3
var name, age = "王五", 28
// 方式3: 短变量批量声明
name, city, country := "赵六", "深圳", "中国"
3. 零值
Go 中每个变量都有零值:
package main
import "fmt"
func main() {
// 声明变量但不初始化
var s string
var i int
var f float64
var b bool
var p *int
fmt.Printf("string零值: %q (长度: %d)n", s, len(s)) // "" (长度: 0)
fmt.Printf("int零值: %dn", i) // 0
fmt.Printf("float64零值: %fn", f) // 0.000000
fmt.Printf("bool零值: %tn", b) // false
fmt.Printf("指针零值: %vn", p) // <nil>
}
常量定义
1. 常量声明
常量使用const关键字声明:
// 单个常量
const PI = 3.14159
const APP_NAME = "MyApp"
const MAX_USERS = 1000
// 批量常量
const (
STATUS_ACTIVE = "active"
STATUS_INACTIVE = "inactive"
STATUS_PENDING = "pending"
)
// 常量组(如果省略值,会沿用前一个值)
const (
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
SUNDAY = 7
)
2. iota 枚举
iota是 Go 的常量生成器:
package main
import "fmt"
// 定义级别枚举
const (
LevelUnknown = iota // 0
LevelLow // 1
LevelMedium // 2
LevelHigh // 3
LevelCritical // 4
)
// 带计算的表达式
const (
_ = iota // 忽略0
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB = 1 << (10 * iota) // 1 << 20 = 1048576
GB = 1 << (10 * iota) // 1 << 30 = 1073741824
)
func main() {
fmt.Printf("LevelLow: %dn", LevelLow)
fmt.Printf("KB: %dn", KB)
fmt.Printf("MB: %dn", MB)
fmt.Printf("GB: %dn", GB)
}
基础数据类型
1. 布尔类型
var isActive bool = true
var isCompleted bool = false
// 布尔运算
func main() {
a := true
b := false
fmt.Printf("a && b = %tn", a && b) // false
fmt.Printf("a || b = %tn", a || b) // true
fmt.Printf("!a = %tn", !a) // false
}
2. 数值类型
整数类型
// 有符号整数
var i8 int8 = 127 // -128 到 127
var i16 int16 = 32767 // -32768 到 32767
var i32 int32 = 2147483647 // -2147483648 到 2147483647
var i64 int64 = 9223372036854775807 // -9.22e18 到 9.22e18
// 无符号整数
var ui8 uint8 = 255 // 0 到 255
var ui16 uint16 = 65535 // 0 到 65535
var ui32 uint32 = 4294967295 // 0 到 4294967295
var ui64 uint64 = 18446744073709551615 // 0 到 1.84e19
// 平台相关类型
var i int = 42 // 32位或64位,取决于平台
var u uint = 42 // 32位或64位无符号整数
var ptr uintptr = 0x123456 // 存放指针的无符号整数
浮点数类型
var f32 float32 = 3.14159 // IEEE-754 32位浮点数
var f64 float64 = 2.718281828 // IEEE-754 64位浮点数
// 浮点数运算
func main() {
var a float64 = 3.14
var b float64 = 2.71
sum := a + b
fmt.Printf("%.2f + %.2f = %.2fn", a, b, sum) // 3.14 + 2.71 = 5.85
}
复数类型
package main
import (
"fmt"
"math/cmplx"
)
var c64 complex64 = 3 + 4i // 32位实数和虚数
var c128 complex128 = 1 + 2i // 64位实数和虚数
func main() {
c := 3 + 4i
fmt.Printf("实部: %f, 虚部: %fn", real(c), imag(c)) // 实部: 3.000000, 虚部: 4.000000
fmt.Printf("模: %fn", cmplx.Abs(c)) // 模: 5.000000
}
3. 字符串类型
// 字符串声明
var s1 string = "Hello, World!"
s2 := "Go语言"
// 多行字符串
s3 := `这是一个
多行字符串
可以包含换行符`
// 字符串操作
func main() {
s := "Hello"
// 字符串连接
greeting := s + ", World!"
fmt.Println(greeting) // Hello, World!
// 字符串长度
fmt.Printf("长度: %dn", len(s)) // 长度: 5
// 字符串索引
fmt.Printf("第一个字符: %cn", s[0]) // 第一个字符: H
// 字符串切片
fmt.Printf("子串: %sn", s[1:3]) // 子串: el
}
4. 字符类型
💡 这里用到了 for 循环与 range 遍历,语法详见 06-control-structures.md。
// byte是uint8的别名,用于ASCII字符
var c1 byte = 'A' // 65
// rune是int32的别名,用于Unicode字符
var c2 rune = '中' // Unicode码点
func main() {
// 遍历字符串的字符
s := "Hello世界"
fmt.Println("按字节遍历:")
for i := 0; i < len(s); i++ {
fmt.Printf("%d: %cn", i, s[i])
}
fmt.Println("n按字符遍历:")
for i, r := range s {
fmt.Printf("%d: %c (码点: %d)n", i, r, r)
}
}
类型转换
1. 显式类型转换
Go 是强类型语言,需要显式转换:
func main() {
var i int = 42
var f float64 = 3.14
// 整数转浮点数
f2 := float64(i)
fmt.Printf("int %d 转为 float64: %fn", i, f2)
// 浮点数转整数(会丢失小数部分)
i2 := int(f)
fmt.Printf("float64 %f 转为 int: %dn", f, i2)
// 不同整数类型间转换
var i16 int16 = 1000
var i8 int8 = int8(i16) // 可能溢出,需要小心
fmt.Printf("int16 %d 转为 int8: %dn", i16, i8)
}
2. 字符串转换
package main
import (
"fmt"
"strconv"
)
func main() {
// 数字转字符串
i := 42
f := 3.14
b := true
si := strconv.Itoa(i) // int转string
sf := strconv.FormatFloat(f, 'f', 2, 64) // float64转string
sb := strconv.FormatBool(b) // bool转string
fmt.Printf("数字转字符串: %s, %s, %sn", si, sf, sb)
// 字符串转数字
s1 := "123"
s2 := "3.14"
s3 := "true"
i2, _ := strconv.Atoi(s1) // string转int
f2, _ := strconv.ParseFloat(s2, 64) // string转float64
b2, _ := strconv.ParseBool(s3) // string转bool
fmt.Printf("字符串转数字: %d, %f, %tn", i2, f2, b2)
}
实际应用示例
示例1: 用户信息管理
💡 这里用到了结构体(
struct),结构体语法详见 04-composite-types.md。
package main
import "fmt"
// 定义用户信息结构
type UserInfo struct {
ID int
Username string
Age int
Email string
IsActive bool
}
func main() {
// 创建用户信息
var user1 UserInfo
user1.ID = 1
user1.Username = "zhangsan"
user1.Age = 25
user1.Email = "zhangsan@example.com"
user1.IsActive = true
// 使用短声明创建第二个用户
user2 := UserInfo{
ID: 2,
Username: "lisi",
Age: 30,
Email: "lisi@example.com",
IsActive: false,
}
// 显示用户信息
displayUser(user1)
displayUser(user2)
}
func displayUser(user UserInfo) {
fmt.Println("=== 用户信息 ===")
fmt.Printf("ID: %dn", user.ID)
fmt.Printf("用户名: %sn", user.Username)
fmt.Printf("年龄: %dn", user.Age)
fmt.Printf("邮箱: %sn", user.Email)
fmt.Printf("状态: %tn", user.IsActive)
fmt.Println("================")
}
示例2: 配置管理
💡 这里用到了
if条件判断与switch多路分支,语法详见 06-control-structures.md。
package main
import "fmt"
// 应用配置常量
const (
APP_NAME = "GoWebApp"
APP_VERSION = "1.0.0"
MAX_CONNECTIONS = 100
// 日志级别(注意:iota 从 const 块首行开始计数,
// 前面已有 3 个常量,因此 LOG_DEBUG 是 3 而不是 0)
LOG_DEBUG = iota // 3
LOG_INFO // 4
LOG_WARN // 5
LOG_ERROR // 6
)
// 配置结构
type Config struct {
Host string
Port int
Debug bool
LogLevel int
}
func main() {
// 使用默认配置
config := Config{
Host: "localhost",
Port: 8080,
Debug: false,
LogLevel: LOG_INFO,
}
// 显示配置信息
fmt.Printf("应用: %s v%sn", APP_NAME, APP_VERSION)
fmt.Printf("最大连接数: %dn", MAX_CONNECTIONS)
fmt.Printf("服务器地址: %s:%dn", config.Host, config.Port)
// 根据配置调整行为
if config.Debug {
fmt.Println("调试模式已启用")
}
switch config.LogLevel {
case LOG_DEBUG:
fmt.Println("日志级别: DEBUG")
case LOG_INFO:
fmt.Println("日志级别: INFO")
case LOG_WARN:
fmt.Println("日志级别: WARN")
case LOG_ERROR:
fmt.Println("日志级别: ERROR")
}
}
示例3: 数据计算
package main
import (
"fmt"
"math"
)
// 计算圆的面积和周长
func calculateCircle(radius float64) (area, circumference float64) {
area = math.Pi * radius * radius
circumference = 2 * math.Pi * radius
return
}
func main() {
// 输入数据
var radius float64 = 5.0
// 计算
area, circumference := calculateCircle(radius)
// 输出结果
fmt.Printf("半径: %.2fn", radius)
fmt.Printf("面积: %.2fn", area)
fmt.Printf("周长: %.2fn", circumference)
// 类型转换示例
areaInt := int(area)
fmt.Printf("面积(整数部分): %dn", areaInt)
}
常见错误和注意事项
1. 类型不匹配错误
// ❌ 错误
var i int = 42
var f float64 = i // 不能直接赋值,需要类型转换
// ✅ 正确
var i int = 42
var f float64 = float64(i)
2. 未使用变量错误
// ❌ 错误
func main() {
var name string = "test" // 声明但未使用
fmt.Println("Hello")
}
// ✅ 正确
func main() {
name := "test"
fmt.Println("Hello,", name) // 使用变量
}
3. 常量类型推断
// ❌ 错误 - 常量必须能在编译时确定值
const x = getNumber() // getNumber()是函数调用
// ✅ 正确
const x = 42
const y = 3.14
const s = "Hello"
性能提示
1. 选择合适的数据类型
// ✅ 选择合适的类型
var age uint8 = 25 // 年龄用uint8足够(0-255)
var count int = 1000000 // 大数量用int
var price float64 = 19.99 // 科学计算中常用;金融金额应按业务选择最小货币单位的整数或十进制类型
2. 避免不必要的类型转换
// ❌ 频繁转换
func process(items []float64) {
for _, item := range items {
i := int(item) // 每次都转换
// 使用i...
}
}
// ✅ 保持类型一致
func process(items []int) {
for _, item := range items {
// 直接使用item...
}
}
文档交叉引用
相关文档
参考资源
- 📖 [Go 数据类型文档]: https://golang.org/ref/spec#Types
- 📖 [Go 常量文档]: https://golang.org/ref/spec#Constants
- 📖 [Go 变量文档]: https://golang.org/ref/spec#Variables
总结
核心要点回顾
- 变量声明: 掌握 var、:=和批量声明方式
- 常量定义: 理解 const 和 iota 的使用
- 数据类型: 熟悉基础数据类型和零值
- 类型转换: 学会显式类型转换的方法
实践练习与验收
创建 profile.go,声明 name(string)、age(int)、active(bool)和一个 Role 常量组:Guest = iota、Member、Admin。在 main 中打印它们,并把 age 转为 float64 后除以 2。
验收:go run profile.go 应退出成功;输出中同时有你的名字、整数年龄、true 或 false,以及 年龄的一半: 12.5(若年龄为 25)。把年龄改成 25.9 后再尝试直接赋给 int 变量:编译器应拒绝该赋值;改成 int(25.9) 后能运行且结果为 25。最后解释:这不是四舍五入,而是向零截断。
提示:先只使用 fmt.Println;常量组不需要变量名数组。完成后再把 Role 用作结构体字段,观察常量的类型如何参与赋值检查。
文档状态: ✅ 已完成最后更新: 2026年9月版本: v1.0.0
💡 学习建议: – 理解 Go 的静态类型系统,与动态语言进行对比 – 多练习类型转换,理解转换可能带来的数据丢失 – 在实际编程中选择合适的数据类型 – 使用常量提高代码的可读性和维护性