flyfei

变量、常量、数据类型

理论/现象/语法

概念 是什么 解决什么问题 语法示例
变量 运行时可改的数据容器 存储中间结果、传递数据 var n int = 10
常量 编译时确定且不可改 统一配置、防止魔数 const pi = 3.14
基本类型 语言内置的单一值类型 决定内存大小与操作 int float64 bool string
复合类型 由基本类型组合而成 描述复杂实体 []int map[string]int struct{}
类型转换 显式把 A 类型变成 B 类型 避免类型不匹配编译错 float64(age)

编码演示

四种变量声明

func main() {
    var s1 string = "Hello" // 标准
    var s2 = "Hello"        // 类型推导
    s3 := "Hello"           // 简短声明(函数内)
    var s4 string           // 零值:""
    fmt.Println(s1, s2, s3, s4)
}

常量 + iota 枚举

const (
    StatusOk = iota // 0
    StatusFailed    // 1
    StatusTimeout   // 2
)

零值演示

var (
    i int     // 0
    f float64 // 0
    b bool    // false
    s string  // ""
)

类型转换

var a int = 42
b := float64(a)      // 数值转换
c := string(rune(a)) // 转 Unicode 字符 "*"

自定义类型

package main

import "fmt"

// 定义两种“单位”类型,防止混用
type Meter float64
type Foot   float64

// 为 Meter 添加方法
func (m Meter) String() string {
	return fmt.Sprintf("%.2f m", m)
}

func main() {
	var (
		height Meter = 1.75
		// 如果把 Foot 赋给 Meter,编译器会报错
		// height = Foot(5.74) // ❌ cannot use Foot(5.74) (type Foot) as type Meter
	)
	fmt.Println("height =", height)
}

// 结构体 == 更强大的自定义类型
type Person struct {
    Name string
    Age  int
}

复合类型

// 数组[0 0 0]
var a [3]int  
b := [3]int{10, 20, 30}
//改 / 查
b[1] = 200
fmt.Println("改后:", b[1])

// 切片
//初始化方式 3 种
s1 := []int{1, 2, 3}          // 字面量
s2 := make([]int, 2, 4)       // 长度 2 容量 4
s3 := new([]int)              // 返回 *切片,很少用
fmt.Println("字面量:", s1, "make:", s2, "new:", *s3)

// 增 / 删 / 改 / 查
s1 = append(s1, 4, 5)         // 增
s1 = append(s1[:2], s1[3:]...) // 删索引2(3被移走)
s1[0] = 100                   // 改
fmt.Println("增删改后:", s1, "长度=", len(s1), "容量=", cap(s1))  
// 遍历
for i, val := range s1 {
	fmt.Printf("%d=%d ", i, val)
}

// map 字典,映射
m1 := map[string]int{"Go": 98, "Rust": 95}
m2 := make(map[string]int) // 空 map 可以写
fmt.Println("字面量:", m1, "make:", m2)

m2["Python"] = 92          // 增 or 改
if v, ok := m2["Python"]; ok {
	fmt.Println("查询:", v)
}
delete(m2, "Python") // 删
fmt.Println("删后:", m2)
// 遍历
for lang, score := range m1 {
	fmt.Printf("%s=%d ", lang, score)
}

其他用法

用法 是什么 为什么 30 秒代码
匿名变量 _ 占位符,丢弃值 避免“未使用”编译错;多返回值时干净 _, err := fmt.Println("ok")
平行赋值 同时给多变量赋值 无需临时变量即可交换;一键解包 a, b = b, a
常量表达式 常量间运算 魔数收敛,一改全改;编译期计算零运行时开销 const MB = 1024 * 1024
新类型 vs 别名 type Meter float64 创建新类型;type Second = float64 仅别名 强类型防止单位混淆;编译器帮你找 bug func distance(d Meter) 传错类型就报错
rune 遍历 rune = Unicode 码点 按“字符”而非字节遍历,汉字不劈断 for _, r := range "你好" { fmt.Printf("%c\n", r) }

总结

  1. 变量:三种写法,记得零值。
    1. 标准写法 var s1 string = "hello"
    2. 类型推导 var s1 = "hello"
    3. 简写 s1 := "hello"
  2. 常量const + iota 做枚举,编译期确定。
  3. 类型
    • 基本类型决定内存大小和可进行的操作;
    • 复合类型描述复杂结构;
    • 自定一类型防止混淆
    • 转换必须显式。
  4. 技巧
    • _ 丢弃、平行赋值、常量表达式、新类型防混淆、rune 遍历 Unicode。

课后练习

  1. 不用第三个变量交换两整数。
  2. iota 定义星期一到日。
  3. 编写函数 average(scoreMap map[string]float64) float64 求平均分