「笔记001」Go语法基础1

2024 年 11 月 20 日 星期三(已编辑)
10
摘要
本文介绍了 Go 语言的基础语法,涵盖变量与常量、控制流、数组与切片、Map、函数与指针、错误处理等方面。变量声明有显式、自动推断、简短声明等方式,常量用const声明。控制流以for循环为主,if-else与switch提供多样化条件处理。数组固定大小、切片动态灵活,Map支持动态键值存储。Go函数支持多返回值,指针简化内存操作,需注意内存安全。错误处理显式,结合多返回值避免错误忽略。强调变量作用域、数据共享和并发安全性。
这篇文章上次修改于 2024 年 11 月 21 日 星期四,可能部分内容已经不适用,如有疑问可询问作者。

阅读此文章之前,你可能需要首先阅读以下的文章才能更好的理解上下文。

「笔记001」Go语法基础1

一、简介

Golang(简称 Go)是由 Google 开发的一种静态强类型、编译型编程语言,因其简洁的语法设计、高效的运行时性能以及强大的并发支持,成为现代编程语言中的佼佼者。Go 语言注重简洁性和开发效率,主要特点包括:快速编译、高效并发模型、垃圾回收以及丰富的标准库支持,尤其适合后端服务开发、高并发程序以及微服务架构。

本文将简略介绍作者学到的 Go 语言的基础语法。


二、变量与常量

1. 变量声明

Go 的变量声明非常灵活,支持以下几种方式:

  • 显式声明:使用 var 关键字指定类型。
  • 自动推断类型:通过赋值自动推断。
  • 简短声明:函数内部使用 :=

示例代码: go var name string = "Go" // 显式声明 age := 10 // 简短声明,自动推断为 int 类型

2. 常量

常量通过 const 声明,表示不可修改的固定值。 go const Pi = 3.14159

知识点讲解:

  • 类型推断:简短声明 := 只适用于函数内部,是 Go 提升代码简洁性的关键。但在类型不明确的情况下,建议显式声明。
  • 作用域:变量作用域依赖于声明位置。在函数内部声明的变量作用域仅限于函数内,而包级变量作用域在整个包中。

注意事项:

  • 避免变量重复声明,特别是在复杂的代码块中可能造成混淆。
  • 使用常量声明替代魔法数字(如 3.14),提升代码可读性。

三、控制流

1. for 循环

Go 的 for 循环是唯一的循环结构,但提供了多种形式:

  • 标准计数器循环go for i := 0; i < 5; i++ { fmt.Println(i) }
  • 条件循环go i := 0 for i < 3 { fmt.Println(i) i++ }
  • 无限循环go for { fmt.Println("Infinite Loop") }

2. if-else 和 switch

  • if-else 语句go if num := 10; num > 5 { fmt.Println("Greater than 5") } else { fmt.Println("Less or equal to 5") }

    • 注意:num 的作用域仅限于 if 块。
  • switch 语句go switch time.Now().Weekday() { case time.Monday: fmt.Println("Start of the week") case time.Sunday: fmt.Println("Weekend") default: fmt.Println("Midweek") } Go 的 switch 无需显式 break,默认跳出当前分支。

知识点讲解:

  • Switch 的多样性:支持多个条件表达式,还可以省略条件,用作多分支的 if-else 替代。
  • 短变量声明:在 ifswitch 中,常结合短变量声明提高代码紧凑性。

注意事项:

  • 循环条件需谨慎,避免无限循环导致程序卡死。
  • 如果需要多个条件表达式匹配同一分支,可用逗号分隔条件。

四、数组与切片

1. 数组

数组是固定大小的,同一数组内元素类型必须一致。 go var arr [5]int = [5]int{1, 2, 3, 4, 5}

2. 切片

切片是动态大小的数组,使用更灵活: go s := []int{1, 2, 3} s = append(s, 4, 5) // 添加元素 fmt.Println(s) // [1, 2, 3, 4, 5]

共享底层数组: 切片操作共享底层数据,因此修改切片内容会影响原始数组: go arr := [3]int{1, 2, 3} s := arr[:] s[0] = 99 fmt.Println(arr) // [99, 2, 3]

知识点讲解:

  • 容量与长度:切片的长度(len)是当前元素数,容量(cap)是从起始位置到底层数组末尾的空间。
  • 切片副本:使用 copy 函数创建独立副本,避免原数据被修改。

注意事项:

  • 使用切片操作时要小心数据共享导致的意外副作用。
  • 如果需要扩展容量,建议提前预估容量大小以减少动态分配次数。

五、Map

Map 是键值对的集合,支持动态大小,但存储是无序的。 go m := map[string]int{"one": 1, "two": 2} m["three"] = 3

检测键是否存在go val, ok := m["one"] if ok { fmt.Println("Key exists with value", val) } else { fmt.Println("Key does not exist") }

知识点讲解:

  • 零值行为:访问不存在的键不会报错,而是返回该值类型的零值。例如:整数返回 0,字符串返回 ""
  • 删除键值对:使用 delete(map, key) 删除指定键。

注意事项:

  • Map 是无序的,遍历时不能假设顺序。
  • 并发操作 Map 时需使用 sync.Map 或加锁,避免数据竞争。

六、函数与指针

1. 函数

Go 支持多返回值和具名返回值: go func divide(a, b int) (result int, err error) { if b == 0 { err = errors.New("division by zero") return } result = a / b return }

2. 指针

Go 中的指针简化了内存操作: go func increment(n *int) { *n++ } num := 5 increment(&num) fmt.Println(num) // 6

知识点讲解:

  • 值传递与引用传递:普通变量在函数中是值传递,无法修改原值,而指针传递可以直接修改变量内容。
  • 指针零值:指针未初始化时为 nil,需避免对 nil 指针解引用。

注意事项:

  • 使用指针时要注意内存安全,避免出现悬挂指针或非法访问。
  • 指针是提升性能的利器,但过多使用会降低代码可读性。

七、错误处理

Go 的错误处理是显式的,通常与多返回值结合使用: go func readFile(filename string) (string, error) { data, err := os.ReadFile(filename) if err != nil { return "", err } return string(data), nil }

通过 errors 包自定义错误: go if err != nil { return "", errors.New("custom error message") }

知识点讲解:

  • 链式错误处理:多个函数调用返回错误时,需逐层检查并处理。
  • 错误包装:可以使用 fmt.Errorf 添加上下文信息。

注意事项:

  • 错误处理代码通常需要集中化,避免错误被忽略。
  • 对关键操作务必检查返回的错误值,确保程序行为正确。

注意总结

  1. 变量作用域:根据需要设置变量的最小作用域范围,减少意外覆盖风险。
  2. 循环与条件:谨慎设置循环条件,避免死循环或漏处理分支。
  3. 数组与切片共享:操作切片时需要注意底层数据共享,适当使用 copy 创建副本。
  4. Map 并发访问:Map 默认不是线程安全的,使用时需加锁或采用并发友好数据结构。
  5. 指针使用:在提升性能的同时需注意指针安全,避免 nil 指针访问。
  6. 错误处理:显式错误返回是 Golang 的特色,应结合上下文进行适当封装,避免错误被忽视。

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...