1.2 变量与数据类型
变量声明
Go 有多种变量声明方式:
方式一:var 关键字
package main
import "fmt"
func main() {
// 声明并指定类型
var name string = "Go语言"
// 声明并让编译器推断类型
var age = 25
// 先声明后赋值(会有零值)
var score float64
score = 95.5
// 批量声明
var (
width int = 100
height int = 200
title string = "画布"
)
fmt.Println(name, age, score)
fmt.Println(width, height, title)
}
方式二::= 短声明(最常用)
func main() {
// 短声明:自动推断类型,只能在函数内使用
name := "Go语言"
age := 25
pi := 3.14159
fmt.Println(name, age, pi)
// 可以同时声明多个变量
x, y := 10, 20
fmt.Println(x, y)
// 交换两个变量的值(Go 的优雅写法)
x, y = y, x
fmt.Println(x, y) // 20, 10
}
⚠️
:=只能在函数内部使用,包级别的变量必须使用var。
零值(Zero Value)
Go 中每种类型都有一个零值,声明但未赋值的变量会自动获得零值:
func main() {
var i int // 0
var f float64 // 0.0
var b bool // false
var s string // ""(空字符串)
var p *int // nil(空指针)
fmt.Println(i, f, b, s, p)
// 输出: 0 0 false <nil>
}
这是 Go 的一个重要设计:所有变量都有确定的初始值,不存在"未初始化"的变量。
基本数据类型
整数类型
func main() {
// 有符号整数
var a int8 = 127 // -128 ~ 127
var b int16 = 32767 // -32768 ~ 32767
var c int32 = 2147483647
var d int64 = 9223372036854775807
// 无符号整数
var e uint8 = 255 // 0 ~ 255(即 byte)
var f uint16 = 65535
// int 和 uint 的大小取决于平台(32位或64位)
var g int = 42
fmt.Println(a, b, c, d, e, f, g)
}
浮点数
func main() {
var f1 float32 = 3.14
var f2 float64 = 3.141592653589793 // 默认浮点类型
fmt.Println(f1, f2)
// 注意浮点数精度问题
fmt.Println(0.1 + 0.2) // 0.30000000000000004
}
字符串
func main() {
// 字符串是不可变的字节序列
s1 := "Hello, 世界"
// 获取长度(字节数,不是字符数)
fmt.Println(len(s1)) // 13 (Hello, = 7字节,世界 = 6字节)
// 获取字符数
fmt.Println(utf8.RuneCountInString(s1)) // 9
// 字符串拼接
s2 := "Hello" + " " + "Go"
fmt.Println(s2)
// 多行字符串(反引号)
s3 := `这是一个
多行字符串
可以包含 "引号" 和 \反斜杠`
fmt.Println(s3)
// 字符串是只读的,不能修改单个字符
// s1[0] = 'h' // ❌ 编译错误
}
布尔值
func main() {
isReady := true
isEmpty := false
// 布尔运算
fmt.Println(isReady && isEmpty) // false(与)
fmt.Println(isReady || isEmpty) // true(或)
fmt.Println(!isReady) // false(非)
// Go 不允许将其他类型当作布尔值
// if 1 { } // ❌ 编译错误,不像 Python/JS
// if "" { } // ❌ 编译错误
}
byte 和 rune
func main() {
// byte 是 uint8 的别名,代表一个 ASCII 字符
var ch byte = 'A'
fmt.Println(ch) // 65(ASCII 码)
fmt.Printf("%c\n", ch) // A
// rune 是 int32 的别名,代表一个 Unicode 字符
var r rune = '中'
fmt.Println(r) // 20013(Unicode 码点)
fmt.Printf("%c\n", r) // 中
// 遍历字符串中的每个字符(rune)
s := "Hello, 世界"
for i, ch := range s {
fmt.Printf("索引 %d: %c\n", i, ch)
}
}
类型转换
Go 不支持隐式类型转换,所有转换必须显式进行:
func main() {
// 整数类型之间的转换
var a int32 = 100
var b int64 = int64(a)
// 浮点数与整数之间
var f float64 = 3.99
var i int = int(f) // 3(截断,不是四舍五入!)
// 字符串与数字之间(需要 strconv 包)
// 这里先简单了解,后面 strconv 章节会详细讲
s := fmt.Sprintf("%d", 42) // int → string
fmt.Println(s) // "42"
fmt.Println(b, i)
}
⚠️ Go 中
int和int64是不同类型!即使在 64 位系统上也需要显式转换。
常量
基本常量
// 常量使用 const 声明,必须在编译期确定值
const Pi = 3.14159
const AppName = "GoTutorial"
// 批量声明
const (
StatusOK = 200
StatusNotFound = 404
StatusError = 500
)
func main() {
fmt.Println(Pi, AppName)
fmt.Println(StatusOK, StatusNotFound, StatusError)
// 常量不能修改
// Pi = 3.14 // ❌ 编译错误
}
iota:常量生成器
iota 是 Go 的一个特殊常量,在 const 块中从 0 开始自增:
// 定义枚举
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
// 配合位运算,定义权限
const (
ReadPermission = 1 << iota // 1 (001)
WritePermission // 2 (010)
ExecutePermission // 4 (100)
)
// 跳过某个值
const (
A = iota // 0
_ // 1(跳过)
C // 2
D // 3
)
// 定义文件大小单位
const (
_ = iota
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20
GB // 1 << 30
TB // 1 << 40
)
func main() {
fmt.Println("Monday:", Monday)
fmt.Println("KB:", KB, "MB:", MB, "GB:", GB)
fmt.Println("Read:", ReadPermission, "Write:", WritePermission)
}
Printf 格式化动词
func main() {
name := "Go"
age := 15
pi := 3.14159
isAwesome := true
fmt.Printf("字符串: %s\n", name) // %s = String 字符串
fmt.Printf("整数: %d\n", age) // %d = Decimal 十进制整数
fmt.Printf("浮点数: %f\n", pi) // %f = Float 浮点数
fmt.Printf("浮点数: %.2f\n", pi) // %.2f = Float 保留2位小数
fmt.Printf("布尔值: %t\n", isAwesome) // %t = Boolean 布尔值
fmt.Printf("类型: %T\n", pi) // %T = Type 变量类型(只有这个大写)
fmt.Printf("通用: %v\n", age) // %v = Value 默认格式
fmt.Printf("二进制: %b\n", 42) // %b = Binary 二进制
fmt.Printf("十六进制: %x\n", 255) // %x = Hexadecimal 十六进制
fmt.Printf("八进制: %o\n", 8) // %o = Octal 八进制
fmt.Printf("字符: %c\n", 65) // %c = Character 字符
fmt.Printf("指针: %p\n", &age) // %p = Pointer 指针地址
}
小结
| 概念 | 要点 |
|---|---|
| 声明方式 | var 用于包级别或需要指定类型;:= 用于函数内的简短声明 |
| 零值 | 所有类型都有零值,不存在未初始化变量 |
| 类型转换 | 必须显式转换,没有隐式转换 |
| 常量 | 编译期确定,iota 用于生成枚举 |
| 字符串 | 不可变,底层是字节序列,用 rune 处理 Unicode |