【Go语言学习系列03】Go基础语法(一):变量与数据类型

📚 原创系列: “Go语言学习系列”

🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。

🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Go技术文章。

📑 Go语言学习系列导航

本文是【Go语言学习系列】的第3篇,当前位于第一阶段(入门篇)

🚀 第一阶段:入门篇
  1. Go语言简介与环境搭建
  2. Go开发工具链介绍
  3. Go基础语法(一):变量与数据类型 👈 当前位置
  4. Go基础语法(二):流程控制
  5. Go基础语法(三):函数
  6. Go基础语法(四):数组与切片
  7. Go基础语法(五):映射
  8. Go基础语法(六):结构体
  9. Go基础语法(七):指针
  10. Go基础语法(八):接口
  11. 错误处理与异常
  12. 第一阶段项目实战:命令行工具

📚 查看完整Go语言学习系列导航

📖 文章导读

本文将深入介绍Go语言的变量与数据类型系统,涵盖:

  • Go变量声明的多种方式及其最佳实践
  • Go的基本数据类型(整数、浮点数、布尔值、字符串)详解
  • 复合数据类型(数组、切片、映射)基础概念
  • 类型转换和类型断言的正确使用方法
  • 常量定义与iota枚举模式的高级技巧
  • 零值机制与变量作用域的全面讲解

无论你是编程新手还是有其他语言经验的开发者,本文都将帮助你全面理解Go语言的类型系统,为后续学习打下坚实基础。

Go数据类型概览


Go基础语法(一):变量与数据类型详解

一、Go语言变量声明

在Go语言中,变量是存储数据的基本单元。相比其他语言,Go提供了多种变量声明方式,满足不同场景的需求。

1.1 变量声明的基本语法

Go语言变量声明有以下几种主要形式:

1) 完整声明形式
var 变量名 类型 = 初始值

例如:

var name string = "Gopher部落"
var age int = 25
var isActive bool = true
2) 类型推导形式

如果提供了初始值,Go编译器可以自动推导变量类型:

var 变量名 = 初始值

例如:

var name = "Gopher部落"  // 自动推导为string类型
var count = 42         // 自动推导为int类型
var pi = 3.14159       // 自动推导为float64类型
3) 短变量声明(最常用)

在函数内部,可以使用更简洁的:=语法:

变量名 := 初始值

例如:

func main() {
    name := "Gopher部落"
    age := 25
    isActive := true
    
    // 使用这些变量...
}

⚠️ 注意:短变量声明(:=)只能在函数内部使用,不能在全局作用域使用。

4) 批量声明

可以一次声明多个变量:

var (
    name     string = "Gopher部落"
    age      int    = 25
    isActive bool   = true
)

// 或者使用短变量声明
func main() {
    name, age, isActive := "Gopher部落", 25, true
}

1.2 变量命名规则与约定

Go语言的变量命名遵循以下规则:

  1. 必须以字母或下划线开头,后跟字母、数字或下划线
  2. 区分大小写countCount是不同的变量
  3. 不能使用关键字作为变量名,如funcvarif

Go社区的命名约定:

  1. 驼峰式命名法

    • 局部变量和私有字段用小驼峰:userNameitemCount
    • 导出(公开)变量和字段用大驼峰:UserNameItemCount
  2. 简洁明了:Go推崇简短的变量名,尤其是在小作用域中

    // 推荐
    for i := 0; i < 10; i++ { ... }
    
    // 不推荐
    for index := 0; index < 10; index++ { ... }
    
  3. 缩略词全大写:如HTTPURLID等(在小驼峰中是httpClient

1.3 零值(Zero Values)机制

Go语言的一个重要特性是所有变量都有默认值,称为"零值":

类型零值
整数类型0
浮点类型0.0
布尔类型false
字符串"" (空字符串)
指针、函数、接口、切片、通道、映射nil
var (
    i int
    f float64
    b bool
    s string
    p *int
)

func main() {
    fmt.Println(i)  // 输出: 0
    fmt.Println(f)  // 输出: 0
    fmt.Println(b)  // 输出: false
    fmt.Println(s)  // 输出: ""
    fmt.Println(p)  // 输出: <nil>
}

🔍 深入理解:Go的零值机制消除了"未初始化变量"的概念,提高了程序安全性,减少了常见错误。

1.4 变量作用域

Go语言变量作用域遵循块级作用域规则:

  1. 全局变量:在函数外声明的变量,可在整个包内访问
  2. 局部变量:在函数或块内声明的变量,只在该函数或块内有效
  3. 包级变量:首字母大写的变量可以被其他包访问(公开变量)
// 包级变量(同一包内可访问)
var counter int = 0

// 公开变量(其他包可访问)
var Version string = "1.0.0"

func incrementCounter() {
    // 局部变量
    localVar := 100
    counter++
    
    // 内部块
    {
        innerVar := 200
        fmt.Println(innerVar)  // 可以访问
    }
    
    // fmt.Println(innerVar)  // 错误:innerVar在这里不可见
}

// fmt.Println(localVar)  // 错误:localVar在这里不可见

二、基本数据类型

Go语言提供了丰富而精简的内置数据类型,让我们逐一了解。

2.1 整数类型

Go提供有符号和无符号整数类型,不同位数满足不同范围需求:

类型描述范围
int88位有符号整数-128 ~ 127
int1616位有符号整数-32,768 ~ 32,767
int32 (rune)32位有符号整数-2,147,483,648 ~ 2,147,483,647
int6464位有符号整数-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
uint8 (byte)8位无符号整数0 ~ 255
uint1616位无符号整数0 ~ 65,535
uint3232位无符号整数0 ~ 4,294,967,295
uint6464位无符号整数0 ~ 18,446,744,073,709,551,615
int取决于平台的有符号整数32位或64位
uint取决于平台的无符号整数32位或64位
uintptr无符号整数,足以存储指针32位或64位
func main() {
    var a int8 = 127  // 最大值
    var b byte = 255  // uint8的最大值
    var c rune = '中'  // 表示Unicode字符
    var d int = 64    // 平台相关,在64位系统上为int64
    
    fmt.Printf("a: %d, 类型: %T\n", a, a)
    fmt.Printf("b: %d, 类型: %T\n", b, b)
    fmt.Printf("c: %c, 类型: %T\n", c, c)
    fmt.Printf("d: %d, 类型: %T\n", d, d)
}

💡 最佳实践:通常使用int类型,除非有特殊需求(如内存优化或二进制操作)才使用特定位数类型。

整数字面量

Go支持不同进制的整数表示:

func main() {
    // 十进制
    decimal := 42
    
    // 二进制
    binary := 0b101010  // 从Go 1.13开始支持
    
    // 八进制
    octal := 0o52       // 从Go 1.13开始推荐使用0o前缀
    oldOctal := 052     // 传统写法,不推荐
    
    // 十六进制
    hex := 0x2A
    
    fmt.Println(decimal, binary, octal, oldOctal, hex)  // 都会打印出42
}

2.2 浮点数类型

Go语言提供两种浮点数类型:

类型描述精度
float3232位浮点数约7位十进制精度
float6464位浮点数约15位十进制精度
func main() {
    var f32 float32 = 3.14159265358979
    var f64 float64 = 3.14159265358979
    
    fmt.Printf("float32: %.10f\n", f32)  // 精度有限,会丢失
    fmt.Printf("float64: %.10f\n", f64)  // 保留更多精度
}
浮点数字面量
func main() {
    // 十进制表示
    pi := 3.14159
    
    // 科学计数法
    avogadro := 6.022e23  // 6.022 × 10²³
    plank := 6.626e-34    // 6.626 × 10⁻³⁴
    
    fmt.Println(pi, avogadro, plank)
}

⚠️ 注意:浮点数计算可能有精度误差,不要直接比较浮点数是否相等。

// 错误的比较方式
if x == y { ... }  // 不可靠

// 正确的比较方式
const epsilon = 1e-9
if math.Abs(x-y) < epsilon { ... }  // 可靠

2.3 复数类型

Go提供内置的复数类型:

类型描述
complex64由两个float32组成的复数
complex128由两个float64组成的复数
func main() {
    // 创建复数
    var c1 complex64 = 1 + 2i
    c2 := complex(3.0, 4.0)  // 使用complex函数创建
    
    // 获取实部和虚部
    real1 := real(c1)
    imag1 := imag(c1)
    
    // 复数运算
    sum := c1 + complex64(c2)
    
    fmt.Printf("c1 = %v\n", c1)
    fmt.Printf("实部: %f, 虚部: %f\n", real1, imag1)
    fmt.Printf("c1 + c2 = %v\n", sum)
}

2.4 布尔类型

Go的布尔类型bool只有两个可能的值:truefalse

func main() {
    var isValid bool = true
    isReady := false
    
    // 布尔运算
    and := isValid && isReady  // 逻辑与
    or := isValid || isReady   // 逻辑或
    not := !isValid            // 逻辑非
    
    fmt.Println(and, or, not)  // false true false
}

📌 小知识:Go中不允许将整数转换为布尔值,如if 1 {}是不合法的。

2.5 字符串类型

Go的字符串是不可变的字节序列,使用UTF-8编码存储Unicode文本。

func main() {
    // 字符串声明
    var name string = "Gopher部落"
    greeting := "你好,世界!"
    
    // 多行字符串(原始字符串)
    multiline := `这是第一行
这是第二行
这是第三行`
    
    // 字符串长度
    byteLen := len(greeting)          // 字节长度
    runeLen := utf8.RuneCountInString(greeting)  // 字符长度
    
    fmt.Println(name)
    fmt.Println(multiline)
    fmt.Printf("字节长度: %d, 字符长度: %d\n", byteLen, runeLen)
}
字符串操作
func main() {
    s1 := "Hello"
    s2 := "World"
    
    // 字符串连接
    s3 := s1 + ", " + s2 + "!"
    fmt.Println(s3)  // Hello, World!
    
    // 字符串切片
    substr := s3[7:12]
    fmt.Println(substr)  // World
    
    // 字符串迭代
    for i, char := range "Go语言" {
        fmt.Printf("索引 %d: %c\n", i, char)
    }
}

🔍 深入理解:Go字符串的range循环返回的是rune(Unicode码点)而不是字节,自动处理UTF-8编码。

2.6 字节和Rune类型

处理字符数据时,Go提供两种类型:

  • byte:表示ASCII字符,是uint8的别名
  • rune:表示Unicode码点,是int32的别名
func main() {
    // byte示例
    var b byte = 'A'
    fmt.Printf("byte: %c, 值: %d\n", b, b)  // byte: A, 值: 65
    
    // rune示例
    var r rune = '中'
    fmt.Printf("rune: %c, 值: %d\n", r, r)  // rune: 中, 值: 20013
    
    // 字符串和rune切片转换
    s := "Hello, 世界"
    runes := []rune(s)
    fmt.Printf("rune数量: %d\n", len(runes))
    
    // 修改字符
    runes[7] = '中'
    runes[8] = '国'
    newStr := string(runes)
    fmt.Println(newStr)  // Hello, 中国
}

三、类型转换

Go是强类型语言,不同类型之间的转换必须显式进行。

3.1 基本类型转换

语法:类型(表达式)

func main() {
    // 整数类型间转换
    var i int = 42
    var i64 int64 = int64(i)
    var i32 int32 = int32(i)
    
    // 浮点数转整数(截断小数部分)
    var f float64 = 3.14
    var i2 int = int(f)  // i2 = 3
    
    // 整数转浮点
    var i3 int = 5
    var f2 float64 = float64(i3)  // f2 = 5.0
    
    fmt.Println(i64, i32, i2, f2)
}

3.2 字符串与基本类型转换

使用标准库strconv包:

import (
    "fmt"
    "strconv"
)

func main() {
    // 整数转字符串
    i := 42
    s1 := strconv.Itoa(i)  // 整数转字符串
    s2 := fmt.Sprintf("%d", i)  // 另一种方式
    
    // 字符串转整数
    s3 := "100"
    i2, err := strconv.Atoi(s3)
    if err != nil {
        fmt.Println("转换错误:", err)
    }
    
    // 字符串转浮点数
    s4 := "3.14"
    f, err := strconv.ParseFloat(s4, 64)
    
    // 字符串转布尔值
    s5 := "true"
    b, err := strconv.ParseBool(s5)
    
    fmt.Println(s1, s2, i2, f, b)
}

3.3 转换注意事项

  1. 数值边界检查:转换到较小类型时注意范围

    var big int64 = 1<<32 - 1
    small := int32(big)  // 可能导致值溢出
    
  2. 精度损失:浮点数转整数会丢失小数部分

    var f float64 = 1.999
    i := int(f)  // i = 1,而不是2
    
  3. 字符串转换失败处理:始终检查错误

    i, err := strconv.Atoi("not a number")
    if err != nil {
        // 处理错误
    }
    

四、常量

常量是在编译时就确定的值,不可改变。

4.1 常量声明

const Pi = 3.14159
const (
    StatusOK    = 200
    StatusError = 500
)

// 类型化常量
const Timeout time.Duration = 30 * time.Second

4.2 无类型常量

Go常量可以是"无类型的",根据上下文确定实际类型:

const (
    Pi    = 3.14159  // 无类型浮点常量
    Truth = true     // 无类型布尔常量
    Name  = "Go"     // 无类型字符串常量
)

func main() {
    var f float32 = Pi     // Pi自动适应为float32
    var f64 float64 = Pi   // Pi自动适应为float64
    var b bool = Truth     // Truth自动适应为bool
    var s string = Name    // Name自动适应为string
    
    fmt.Printf("%T %T %T %T\n", f, f64, b, s)
}

4.3 iota与枚举

iota是Go的常量计数器,常用于枚举值:

const (
    Sunday = iota     // 0
    Monday            // 1
    Tuesday           // 2
    Wednesday         // 3
    Thursday          // 4
    Friday            // 5
    Saturday          // 6
)
iota高级用法
const (
    _           = iota             // 跳过0值
    KB          = 1 << (10 * iota) // 1 << 10 = 1024
    MB                             // 1 << 20
    GB                             // 1 << 30
    TB                             // 1 << 40
)

const (
    Readable   = 1 << iota // 1
    Writable              // 2
    Executable            // 4
)

// 权限组合
func checkPermissions(perm int) {
    fmt.Printf("读权限: %v\n", perm&Readable == Readable)
    fmt.Printf("写权限: %v\n", perm&Writable == Writable)
    fmt.Printf("执行权限: %v\n", perm&Executable == Executable)
}

func main() {
    fmt.Println(KB, MB, GB, TB)
    
    rwPerm := Readable | Writable  // 组合权限
    checkPermissions(rwPerm)
}

👨‍💻 关于作者与Gopher部落

"Gopher部落"专注于Go语言技术分享,提供从入门到精通的完整学习路线。

🌟 为什么关注我们?

  1. 系统化学习路径:本系列12篇文章循序渐进,带你完整掌握Go开发
  2. 实战驱动教学:理论结合实践,每篇文章都有可操作的代码示例
  3. 持续更新内容:定期分享最新Go生态技术动态与大厂实践经验
  4. 专业技术社区:加入我们的技术交流群,与众多Go开发者共同成长

📱 关注方式

  1. 微信公众号:搜索 “Gopher部落”“GopherTribe”
  2. 优快云专栏:点击页面右上角"关注"按钮

💡 读者福利

关注公众号回复 “Go学习” 即可获取:

  • 完整Go学习路线图
  • Go面试题大全PDF
  • Go项目实战源码
  • 定制学习计划指导

期待与您在Go语言的学习旅程中共同成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gopher部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值