Go 语言入门指南:基础语法和常用特性解析| 豆包MarsCode AI刷题

117 阅读6分钟

1 什么是Go语言

Go语言,又称为Golang,是一种静态强类型、编译型的开源编程语言。作为一款较新的编程语言,Go语言的一些主要特点包括:

  1. 高性能、高并发:

    Go语言在设计时就考虑到了现代多核处理器的并发需求。它提供了goroutine轻量级线程和channel同步机制,使得并发编程变得简单高效

  2. 语法简单,学习曲线平缓

    Go语言的语法简洁,没有复杂的继承和模板等特性,使得新程序员可以快速上手。它的设计哲学是“少即是多”,避免了不必要的复杂性,使得代码更加清晰易懂。这种简洁的语法也有助于减少编程错误,降低维护成本。

  3. 丰富的标准库

    Go语言拥有一个功能强大的标准库,覆盖了文件处理、网络编程、加密算法、JSON处理等多个领域。无需装载许多复杂的外部库,从而避免版本不兼容的问题

  4. 完善的工具链

    Go语言提供了一套完善的工具链,包括gofmt(代码格式化工具)、go vet(静态分析工具)、go test(测试工具)等。这些工具帮助开发者编写更规范、更安全的代码,自动化测试和代码审查流程,提高开发效率和代码质量。

  5. 静态链接

    Go语言支持静态链接,这意味着编译后的二进制文件包含了所有必要的库和依赖,不需要在运行时依赖特定的系统库。这使得Go程序更容易分发和部署,特别是在不同的操作系统和环境中。

  6. 快速编译

    Go语言的编译速度非常快,这得益于其简洁的语法和编译器的优化。快速编译可以缩短开发周期,提高开发效率,尤其是在进行频繁的代码修改和测试时。

  7. 跨平台

    Go语言支持跨平台编译,开发者可以在一个平台上编译代码,然后在另一个平台上运行。这使得Go语言非常适合开发需要在多个操作系统上运行的应用程序,如Linux、Windows和macOS。

  8. 垃圾回收

    Go语言内置了垃圾回收机制,自动管理内存的分配和释放。这大大简化了内存管理,减少了内存泄漏和悬挂指针的风险。

2 基础语法

首先我们可以从一个HelloWorld的基础程序进行分析

package main

import "fmt"

func main() {
    fmt.Println("hello world!")
}

每个Go程序的开头的是一个package声明,表面该程序所属的包,要创建一个可运行的程序,必须声明一个名字为main的包,同时有一个名字为main的函数

在包声明之后,是import的语句,用于导入该程序所依赖的包。由于我们使用到了println方法,所以需要导入相应的fmt包

所有Go函数以关键字func开头,一个常规的函数定义包含以下部分:

func 函数名(参数列表)(返回值列表) {
    // 函数体
}

注:main函数不能带参数,也不能有返回值

2.1 命名

Go作为强语言类型,对于命名有着严格要求:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。大写字母和小写字母是不同的

2.2 变量

Go中变量声明使用var关键字,可以省略类型进行类型推断

var a int = 10
b := 20 // 类型推断

常量用const定义

2.3 基础语法

2.3.1 if else

if后的条件不加括号

if 条件 {
  执行语句
} else if 条件 {
  执行语句
} else {
  执行语句
}

2.3.2 循环

for循环

Go中只有for循环,没有while循环

在循环条件的设定上,也与Java的很像

  for 初始化; 条件; 后置操作 {
    // 循环体
}
#更加简洁
  for 条件 {
    // 循环体
}
#无限循环
  for {
    // 循环体
}
range循环

range循环用于遍历数组、切片、字符串或映射(map)的元素。它返回两个值:元素的索引(或键)和元素的值

  for index, value := range array {
    // 使用index和value
}
#只关心值的情况
  for _, value := range array {
    // 使用value
}

2.3.3 switch

跟Java不同的是,Go的switch语句在每个case后不需要break语句。一旦找到匹配的case,就会执行该case下的代码块,并自动终止,不会继续执行后续的case

同时,Go的switch语句中的case表达式不必是常量,可以是任何类型的值,包括非常量和非整数类型

如果你想让switch继续执行到下一个case,即使已经找到了匹配的case,可以使用**fallthrough**关键字

2.4 基础数据类型

image.png

Go语言中不允许隐式转换,所有类型转换必须显式声明,而且转换只能发生在两种相互兼容的类型之间

2.5 数据结构

2.5.1 数组

var a [n] int
b :=[5]int(1,2,3,4,5)

Go语言中的数组具有固定的长度,这在声明数组时必须指定。数组的长度是数组类型的一个部分,因此 [10]int[20]int 是两种不同的数组类型。

跟Java不一样的是,Go中的数组是值类型。当数组被赋值或者作为参数传递给函数时,会进行拷贝操作,而不是传递引用。这意味着Go语言可以直接比较两个数组是否相等,只要它们的长度和元素都相同,但对于大型数组,复制时可能会存在性能问题。

2.5.2 切片

Go语言中的切片(slice)是一种基于数组的、更高级的数据结构,它提供了对数组的灵活访问和操作。切片在Go中非常常用,因为它们比固定长度的数组更加灵活。

切片是引用类型,它们指向底层的数组。因此,当切片被赋值或传递给函数时,它们共享相同的底层数组数据,而不是复制数据

// 基于数组
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // 创建一个切片,包含数组的第2到第4个元素

// 使用make函数
slice := make([]int, 5, 10) // 分配一个长度为5,容量为10的切片

// 使用字面量
slice := []int{1, 2, 3, 4, 5}

切片有两个相关的属性:Len()(长度)和Cap()(容量)。长度是切片中元素的数量,而容量是从切片的开始位置到其底层数组末尾的元素数量,容量是大于等于长度的,可以通过append()向切片增加元素

2.5.3 map

类似于其他语言中的哈希表和字典,是K-V数据结构

// 使用make函数
m := make(map[string]int)

// 使用字面量
m := map[string]int{"key1": 1, "key2": 2}

要注意的是,Go中的map是无序化的

2.5.4 指针

在Go中,使用*操作符来声明指针变量,*放在变量类型前表示这是一个指针类型

指针存储了另一个变量的内存地址。通过指针,可以直接访问和操作变量的内存空间,这使得指针成为一种强大的工具,尤其是在需要直接访问和修改变量值的场景中

var p *int // p 是一个指向int类型变量的指针