1.2 golang变量与数据类型

2 阅读5分钟

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 中 intint64 是不同类型!即使在 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