Go快速入门:基础语法 | 豆包MarsCode AI刷题

148 阅读8分钟

Go 语言的用途

Go 语言(Golang)是一种由 Google 开发的编程语言,旨在提供简洁、快速和高效的并发支持,专为解决大型分布式系统中的实际需求而设计。Go 语言广泛用于构建 Web 服务器、分布式系统和高性能后台服务。例如,Kubernetes、Docker 和 InfluxDB 等知名项目都采用 Go 编写,主要因为它的编译速度快、执行效率高、并发支持好以及提供了简洁的语言语法。

Go 语言的设计哲学在于简化代码和优化性能,使得开发者更关注逻辑本身而非代码组织。在实际应用中,Go 语言特别适合需要高并发、高性能的服务场景。


执行 Go 语言程序

Go 语言程序执行的两种常见方式:

  • 使用 go run 命令执行源文件,无需生成二进制文件;
  • 使用 go build 命令生成可执行的二进制文件,适用于生产环境。

通过 go rungo build 提供了灵活的执行方式。在开发阶段,可以直接使用 go run 快速测试;而在生产环境中,则使用 go build 生成的二进制文件以获得更高的性能和稳定性。


Go 变量声明

Go 语言支持多种变量声明方式,满足不同场景的需求:

  1. 指定类型声明,未初始化的变量默认零值:
// 声明一个变量并初始化  
    var a = "RUNOOB"  
    fmt.Println(a)  
  
    // 没有初始化就为零值  
    var b int  
    fmt.Println(b)  
  
    // bool 零值为 false  
    var c bool  
    fmt.Println(c)  
  1. 自动类型推断,无需指定类型:
 var d = true  
  1. 简短声明,使用 :=,适用于局部变量:
f := "Runoob" //等价于 var f string = "Runoob" 

Go 语言的变量声明方式丰富,尤其是在开发中使用 := 简写赋值大大提高了代码的简洁性和可读性。不过需要注意的是,:= 只能用于函数内部,而不能在全局作用域中使用。


Go 语言的格式化输出

Go 提供 fmt.Sprintffmt.Printf 两种格式化输出方式:

  • Sprintf 返回格式化字符串,适合赋值;
  • Printf 将格式化字符串直接输出到控制台。

使用示例

package main

import "fmt"

func main() {
    var stockcode = 123
    var enddate = "2020-12-31"
    url := fmt.Sprintf("Code=%d&endDate=%s", stockcode, enddate)
    fmt.Println(url)
     
}
package main  
  
import (  
    "fmt"  
)  
  
func main() {  
   // %d 表示整型数字,%s 表示字符串  
    var stockcode=123  
    var enddate="2020-12-31"  
    var url="Code=%d&endDate=%s"  
    fmt.Printf(url,stockcode,enddate)  
}

Go 语言的 fmt 包设计直观,符合 C 系语言用户的使用习惯。通过灵活的格式化选项,开发者可以在生成复杂的日志信息时保持代码的可读性和维护性。


Go 语言函数

Go 语言函数支持多返回值,这在其他静态类型语言中较少见。多返回值可以简化错误处理和状态反馈,提高代码健壮性。

示例

func swap(x, y string) (string, string) {
   return y, x
}

多返回值的设计降低了额外的结构体封装成本,在处理需要返回多种状态的函数时特别有用。不过,过多的返回值可能会增加代码复杂度,因此在实际使用中需保持平衡。


Go 语言指针

Go 语言提供了指针支持,但没有指针运算。取地址符 & 和解引用符 * 使得 Go 能够在保留高效内存操作的同时保持安全性。Go 语言的垃圾回收机制也简化了内存管理,减少了开发者在指针使用上的负担。

示例

package main

import "fmt"

func main() {
    var a = 42
    var ptr = &a
    fmt.Println("a 的地址:", ptr)
    fmt.Println("a 的值:", *ptr)
}

Go 在保持 C 语言效率的同时,避免了因指针操作产生的安全性问题,特别是在多线程环境中提供了更高的安全保障。


Go 语言结构体

Go 语言使用 struct 来定义结构体,可存储多种数据类型。结构体让 Go 语言在面向对象设计上更加简洁,但又没有引入复杂的继承关系。结构体通过 typestruct 关键字声明。

示例

type Person struct {
    name string
    age  int
}

结构体的简洁设计让 Go 在保持性能的前提下具备了面向对象特性。在需要封装多种类型数据的场景中,结构体特别适用,如数据库表结构映射和数据聚合。


Go 语言切片

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组")。切片是一种基于数组的动态大小序列,它提供了一种灵活的方式来处理数据集合。切片在内部由三个要素组成:指向底层数组的指针、切片的长度以及切片的容量。切片的长度是切片中元素的数量,而容量是切片可以增长到的最大长度。

创建和初始化切片

slice1 := make([]type, len,cap)

len是数组的长度并且也是切片的初始长度, cap表示指定容量 为可选参数。

访问和修改切片元素

切片中的元素可以通过索引来访问和修改切片中的元素。

切片的长度和容量

切片的长度和容量可以通过切片的 lencap 函数获得。

fmt.Println(len(s)) // 打印切片的长度
fmt.Println(cap(s)) // 打印切片的容量

切片的动态调整

切片的长度可以动态调整,切片的容量决定了切片可以增长的最大长度
append 函数可以将一个或多个元素添加到切片的末尾。 append 函数会返回新的切片,如果当前容量不足以容纳新元素,Go 运行时会进行容量增长操作。
= 可以用于重新设置切片的长度。这会截断开切片,丢弃超出新长度的部分。

s := []int{1, 2, 3}
s = append(s, 4,5) // 添加多个元素
fmt.Println(s) // 输出: [1 2 3 4]
s = s[:len(s)/2] // 将切片长度设置为原长度的一半
fmt.Println(s) // 输出: [1 2]

切片的复制和连接

切片可以使用 copy 函数复制切片,使用 append 函数可以将一个切片的所有元素添加到另一个切片的末尾。这实质上是创建了两个切片的新副本,并将它们连接起来。

src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src) // 复制src到dst
fmt.Println(dst) // 输出: [1 2 3]

s1 := []int{1, 2, 3}
s2 := []int{4, 5}
s3 := make([]int, len(s1)+len(s2))
s3 = append(s3, s1...) // 将s1的所有元素添加到s3
s3 = append(s3, s2...) // 将s2的所有元素添加到s3
fmt.Println(s3) // 输出: [1 2 3 4 5]

切片的遍历

可以通过range关键字进行遍历。使用range遍历切片时,range会返回切片中每个元素的索引和值。

package main

import "fmt"

func main() {
    s := []int{10, 20, 30, 40, 50}
    for i, v := range s {
       // i 是索引,v 是对应索引处的值
        fmt.Println(i, v)
    }
}

Go Map集合

Map 是一种无序的键值对的集合。

Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的。

在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 ""。

Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。

声明和初始化

var map1 map[KeyType]ValueType           // 声明
map1 = make(map[KeyType]ValueType)       // 初始化
map2 := make(map[KeyType]ValueType)      // 声明并初始化
map3 := map[KeyType]ValueType{}          // 声明并初始化空map

// 直接初始化带有数据的map
map4 := map[string]int{
    "apple": 1,
    "banana": 2,
}

Map的基本操作

// 获取键值对
v1 := m["apple"]
v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值
m["apple"] = 5
len := len(m)
for k, v := range m {
    fmt.Printf("key=%s, value=%d\n", k, v)
}
delete(m, "banana")

总结

Go 语言通过简洁的语法、强大的并发支持以及高效的性能表现,在系统编程和网络应用领域具有很大优势。它的指针、结构体、切片、Map 等功能为开发者提供了强大的数据结构管理能力,同时通过编译期优化提升了代码的执行效率。Go 的简洁性和高效性在分布式系统和高并发应用中得到了广泛应用。

Go 语言在保留底层性能优势的同时,极大简化了语法和内存管理,适合追求高效开发的场景。希望通过本文的讲解,让读者对 Go 的各个模块有更清晰的理解,并能更好地在实践中应用。