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

33 阅读11分钟

1. 安装和配置Go环境

  • 安装Go:访问Go官网下载对应操作系统的安装包,并按照指引完成安装。
  • 配置环境变量:确保GOPATHGOROOT环境变量已正确设置。可在命令行中输入go version进行检查。
  • 豆包MarsCode IDE:在豆包MarsCode中可以创建云上的虚拟环境,更快启动项目进行学习与测试。

2.Go程序基本框架

我们以Hello world为例子概述go程序的结构,首先导入一个包package mainpackage main 是一个包声明语句,用于表明当前 Go 源文件所属的包名。在 Go 语言里,代码是通过包(package)来组织和模块化管理的。所有的 Go 代码都必须属于某个包,包就像是代码的容器,把相关的类型、函数、变量等元素组织在一起,方便复用、维护以及代码的逻辑划分。

package main

import "fmt"

func main() {
	fmt.Println("Hello world")
}

Go语言可以导入其他的 Go 包来使用它们提供的功能,同时其他包也可以被其他项目中的不同包复用。使用import关键字导入相关包,其中fmt包用于格式化输入输出,go应用程序的函数主体为func main,是程序的主入口即程序代码开始执行的地方,上面的示例程序会输出一行“Hello world”。

3.Go语言的编译和运行

  • 使用go build命令编译

    • 这是最常用的编译方式。在命令行中,进入包含 Go 源文件(通常是package main文件)的目录,然后执行go build命令。例如,如果你的 Go 源文件名为main.go,执行go build后,会在当前目录下生成一个可执行文件(在 Linux 和 macOS 下默认没有文件扩展名,在 Windows 下是.exe文件)。如果项目中有多个源文件,go build会自动查找并编译所有相关的文件。
  • 使用go run命令编译并执行

    • 当你只是想快速测试一段 Go 代码时,可以使用go run命令。例如,go run main.go会先编译main.go文件(以及它所依赖的其他文件),然后立即执行生成的可执行文件。这种方式不会在当前目录下留下编译后的可执行文件,适合用于开发过程中的快速验证。
  • 跨平台编译

    • Go 语言支持跨平台编译。通过设置环境变量GOOS(目标操作系统)和GOARCH(目标架构),可以在一个平台上编译出用于其他平台的可执行文件。例如,要在 Linux 平台上编译一个用于 Windows 的可执行文件,可以执行GOOS = windows GOARCH = amd64 go build命令。

4.变量的声明与定义

var age int
var name string = "John"
var a,b,c int
var x,y,z = 1,"two",true
age := 25
a,b := 1,2
  • 变量声明

    • 单一变量声明

      • 在 Go 语言中,使用var关键字来声明变量。例如,var age int声明了一个名为age的整数类型变量。此时变量被声明,但还没有初始化,它会被赋予该类型的零值。对于整数类型,零值是0
      • 也可以在声明变量的同时进行初始化,如var name string = "John",这里声明了一个名为name的字符串变量,并初始化为"John"
    • 多个变量声明

      • 可以使用var一次声明多个变量,变量之间用逗号隔开。例如,var a, b, c int声明了三个整数类型变量abc,它们的初始值都是0
      • 也可以在声明多个变量时进行不同的初始化,如var x, y, z = 1, "two", true,这里x被初始化为1(类型为整数),y被初始化为"two"(类型为字符串),z被初始化为true(类型为布尔值)。Go 语言会根据初始化的值自动推断变量的类型。
  • 变量定义(简短变量声明)

    • Go 语言提供了简短变量声明的方式,使用:=操作符。例如,age := 25,这里不仅声明了变量age,还同nil:在 Go 语言中,nil是一个特殊的值,用于表示指针、接口、映射(map)、切片(slice)和通道(channel)等类型的零值或未初始化状态。例如,对于指针类型,当声明一个指针变量但未对其赋值时,它的值为nil。这里,i := 0是初始化语句,用于初始化循环变量ii < 5是条件表达式,只要这个条件为真,循环就会继续;i++是后置语句,在每次循环体执行完后执行,通常用于更新循环变量。这个循环会输出04

for - range循环(用于遍历容器类型) :在Go语言中,for - range循环用于遍历数组、切片、字符串、映射(map)等容器类型。例如,遍历切片:

slice := []string{"apple", "banana", "cherry"}
for index, value := range slice {
   println(index, value)
}

这里,index表示元素的索引(对于数组、切片等),value表示元素的值。在每次循环中,indexvalue会被更新为下一个元素的索引和值。对于映射,index表示键(key),value表示值。如果只需要值,可以使用for _, value := range slice的形式,其中_表示忽略索引。

  • 分支结构

if - else语句

	num :=9
	if num < 0 {
		fmt.Println(num, "is negative")
	} else if num < 10 {
		fmt.Println(num, "has 1 digit")
	} else {
		fmt.Println(num, "has multiple digits")
	}

上述代码中首先声明并创建了一个整体变量num 并赋值为9,其不满足第一个if分支,往下检查发现满足if-else分支,那么就执行此代码块,如果不满足则执行else分支里面的代码块。

switch语句

switch语句用于多分支选择。基本形式为switch表达式 { case值1: 执行代码块1; case值2: 执行代码块2;... default: 执行代码块n }。例如:

day := 3
switch day {
case 1:
   println("星期一")
case 2:
   println("星期二")
case 3:
   println("星期三")
//...
default:
   println("其他")
}

switch后面的表达式(这里是day)的值与某个case后面的值匹配时,就会执行对应的代码块。如果没有匹配的case,就会执行default代码块(default部分是可选的)。

6.数组,slice,映射MAP

数组

  • 定义与初始化

    • 在 Go 语言中,数组是具有固定长度的同类型元素的序列。定义数组时需要指定元素类型和数组长度。例如,var numbers [5]int定义了一个包含 5 个整数元素的数组,数组中的元素初始值为 0(因为int类型的零值是 0)。
    • 也可以在定义数组时进行初始化,如var fruits = [3]string{"apple", "banana", "cherry"},这里定义了一个长度为 3 的字符串数组,并初始化为三个水果名称。
  • 访问元素

    • 通过索引来访问数组中的元素,索引从 0 开始。例如,对于上面定义的numbers数组,numbers[0]表示访问第一个元素,numbers[4]表示访问最后一个元素。可以对数组元素进行读取和赋值操作,如numbers[2] = 10,将数组中索引为 2 的元素赋值为 10。
  • 数组的长度

    • 使用len()函数来获取数组的长度。例如,对于fruits数组,len(fruits)会返回 3。数组的长度是其类型的一部分,这意味着[3]int[5]int是不同的类型,不能直接相互赋值。
  • 数组的遍历

    • 可以使用for循环来遍历数组。例如:
for i := 0; i < len(numbers); i++ {
   println(numbers[i])
}

也可以使用for - range循环来遍历数组,这种方式更加简洁,并且在不需要索引时可以忽略索引变量。例如:

for _, number := range numbers {
   println(number)
}

切片(Slice)

  • 定义与初始化

    • 切片是对数组的一个引用片段,它本身不存储数据,而是通过引用底层数组来提供数据访问。可以通过多种方式创建切片。例如,从数组创建切片:numbers := [5]int{1, 2, 3, 4, 5}slice := numbers[1:4],这里slice是一个切片,它引用了numbers数组中索引从 1(包含)到 4(不包含)的元素,即{2, 3, 4}
    • 还可以使用make函数来创建切片,如slice := make([]int, 3, 5),这创建了一个int类型的切片,长度为 3(即切片中当前有 3 个元素),容量为 5(切片底层数组的长度为 5,容量决定了切片可以扩展的最大长度)。
  • 访问元素和修改元素

    • 切片元素的访问方式和数组类似,通过索引访问。例如,对于上面创建的sliceslice[0]访问第一个元素。可以对切片元素进行修改,修改会反映到底层数组中。例如,slice[1] = 10会修改切片中的第二个元素,同时也会修改底层数组中对应的元素。
  • 切片的长度和容量

    • 切片的长度可以使用len()函数获取,容量可以使用cap()函数获取。例如,对于slice := make([]int, 3, 5)len(slice)返回 3,cap(slice)返回 5。切片的长度小于等于容量,当切片长度小于容量时,可以通过append操作来添加新元素,直到切片长度达到容量。
  • 切片的操作

    • append操作:用于向切片添加新元素。例如,slice = append(slice, 6)会在切片末尾添加一个元素 6。如果切片的长度达到容量,append操作会自动分配一个更大的底层数组,并将原来的数据复制过去。
    • copy操作:用于将一个切片中的元素复制到另一个切片中。例如,slice1 := []int{1, 2, 3}slice2 := make([]int, 3)copy(slice2, slice1)会将slice1中的元素复制到slice2中。
    • 切片的切片(子切片) :可以从一个切片中再创建子切片,方式和从数组创建切片类似。例如,slice := []int{1, 2, 3, 4, 5}subSlice := slice[1:4],这里subSliceslice的一个子切片,包含{2, 3, 4}

映射(Map)

  • 定义与初始化

    • 映射(在其他编程语言中也称为字典、哈希表等)是一种无序的键 - 值对(key - value)数据结构。在 Go 语言中,使用map关键字来定义映射。例如,var ages map[string]int声明了一个映射,键是字符串类型,值是整数类型,但此时这个映射还没有初始化,它的值是nil,不能直接使用,需要使用make函数进行初始化,如ages = make(map[string]int)
    • 也可以在定义映射时进行初始化,如students := map[string]int{"Alice": 20, "Bob": 22},这里创建了一个键为学生名字(字符串),值为学生年龄(整数)的映射,并初始化为两个学生的信息。
  • 访问和修改元素

    • 通过键来访问映射中的值。例如,对于students映射,students["Alice"]可以获取Alice对应的年龄。如果键不存在,会返回值类型的零值。可以通过赋值来修改映射中的值,如students["Alice"] = 21,修改Alice对应的年龄为 21。
  • 元素的插入和删除

    • 插入元素可以通过赋值操作实现,如students["Charlie"] = 23,在students映射中插入一个新的学生Charlie的年龄信息。删除元素可以使用delete函数,如delete(students, "Bob"),会删除students映射中键为Bob的元素。
  • 映射的遍历

    • 使用for - range循环来遍历映射。例如:
for key, value := range students {
   println(key, value)
}

7.函数与返回值

  1. 函数定义 ◦ 在 Go 语言中,函数使用func关键字来定义。函数定义的基本格式为func 函数名(参数列表) 返回值类型 { 函数体 }。例如,func add(num1, num2 int) int { return num1 + num2 }定义了一个名为add的函数,它接受两个整数参数num1num2,并返回它们的和,返回值类型也是整数。 ◦ 函数名遵循 Go 语言的标识符命名规则,参数列表中的参数可以是不同类型的变量,多个参数之间用逗号隔开。如果函数没有参数,参数列表可以为空,如func printHello() { println("Hello") }
  2. 返回值 在Go语言中,函数的返回值可以有多个,比如如下的例子
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}

多个返回值的定义在函数名和形参后面的括号内进行声明即可,这时候调用者会获得多个返回值。