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

76 阅读6分钟

Go语言简介

2007年末由Robert Griesemer, Rob Pike(Bell实验室最早Unix开发者之一), Ken Thompson(C和Unix的发明人,图灵奖得主)在Google公司主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。 image.png

特点:

  • 静态类型语言。
  • 语言层面支持并发。
  • 内置runtime,支持垃圾回收。
  • 简单易学,语言简洁。
  • 丰富的标准库。
  • 内置强大的工具。
  • 跨平台编译。

Go下载地址是:golang.google.cn/dl/

语法特征

  • 包系统
  • 变量与赋值
  • 动态列表slice
  • 词法作用域
  • 一等公民函数
  • 系统调用接口

未实现的功能:

  • 隐式数值类型强制转换
  • 构造函数和析构函数
  • 运算符重载、默认参数、继承、异常、宏、线程局部存储

数据类型

语法特点:类型后置

基本数据类型:

# 整型
var i int8 = 1
# 浮点数
var f float32 = 1.1
#常量
const e = 2.1
#复数
var x complex128 = complex(1,2)
var y complex128 = complex(3,4)
#布尔
var a bool = true
#字符串
s := "hello, world"

复合类型

#数组
var q [4]int = [4]int{1,2,3,4}

#Slice
months := [...]string{1:"January", /*...*/, 12: "December"}

#map
ages := make(map[string]int)

#结构体
type Employee struct{
    ID int
    Name string
}

#json
object{
    "year": 1980,
    "event": "archery",
    "medals": ["gold", "silver", "bronze"]
}

赋值

=是赋值,:=是声明变量并赋值 =的使用必须使用先var声明例如:

var a
a=100
//或
var b = 100
//或
var c int = 100

:=是声明并赋值,并且系统自动推断类型,不需要var关键字

d := 100

多变量赋值,例如b, a = a, b直接交换变量取值

循环

for循环

for i := 0; i < 5; i++ {
fmt.Println(i) 
}

无限循环

for { 
fmt.Println("Infinite loop") 
}

键值循环

for range 结构是一种迭代结构,可以遍历数组、切片、字符串、map 及通道(channel),一般形式为:

for key, val := range coll {
    ...
}

//i.e.
for key, val := range []int{1,2,3}{
    fmt.Println("key:%d, value:%d\n", key, value) 
}

输出:
key:0, value:1
key:1, value:2
key:2, value:3

通过 for range 遍历的返回值有一定的规律:

  • 数组、切片、字符串返回索引和值。
  • map 返回键和值。
  • 通道(channel)只返回通道内的值。

数组与Slice

Go语言的数组和C语言的数组在数据结构上是一样的,相同点都是开一个连续的空间存储数据;两种语言编写的静态数组和动态数组在内存分配方式上几乎相同

动态数组分配上,而C语言采用的实际开空间的模式,借用我们常用的malloc等函数,而Go语言的动态数组实际上是一段内存地址指向的模式,也就是动态列表slice。

Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个 slice 类型一般写作 []T,其中T代表 slice 中元素的类型;slice 的语法和数组很像,只是没有固定长度而已。

一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。

多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠。

slice := []int{1, 2, 3}
slice = append(slice, 4)

一等公民函数

在编程语言设计中,给定编程语言中的一等公民(也就是类型,对象,实体或值)可以把函数赋值给变量,也可以把函数作为其它函数的参数或者返回值来直接使用。Go语言中的函数就满足这一定义。

Go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一些简单的功能。所谓匿名函数,就是没有名称的函数。

hello := function(name string){
fmt.Println("hello %v", name)
}

hello("juejin")

函数被看作第一类值(first-class values):函数像其他值一样,拥有类型,可以被赋值给其他变量,传递给函数,从函数返回。对函数值(function value)的调用类似函数调用。

函数闭包

在Go中,闭包在底层是一个结构体对象,它包含了函数指针与自由变量。Go编译器的逃逸分析机制,会将闭包对象分配至堆中,这样自由变量就不会随着函数栈的销毁而消失,它能依附着闭包实体而一直存在。

垃圾回收

Go1.3 标记清除法

Go1.5 三色标记法

Go1.8 三色标记+混合写屏障

并发

Go语言作为新兴的语言,最近发展势头很是迅猛,其最大的特点就是原生支持并发。它使用的是“协程(goroutine)模型”,和传统基于 OS 线程和进程实现不同,Go语言的并发是基于用户态的并发,这种并发方式就变得非常轻量,能够轻松运行几万并发逻辑。Go 的并发属于 CSP 并发模型的一种实现,CSP 并发模型的核心概念是:“不要通过共享内存来通信,而应该通过通信来共享内存”。这在 Go 语言中的实现就是 Goroutine 和 Channel。

每一个并发的执行单元叫作一个 goroutine。一个 goroutine 可类比一个线程。

go func() { 
    fmt.Println("Running in a goroutine") 
}()

Channels用于不同Goroutines之间的通信,确保数据的同步

ch := make(chan string) go func() { 
    ch <- "Hello from Goroutine" 
}() 
fmt.Println(<-ch) // 输出:Hello from Goroutine

错误处理

Go 提供了一种简洁而有效的错误处理机制,通过 error 类型来表示错误。Go 的错误处理遵循一种显式而简单的方式,函数通常返回一个错误值,如果没有错误,返回值为 nil。

if err != nil { 
    log.Fatal(err) 
}

总结

Go 语言是一种功能强大且特色鲜明的编程语言,它融合了静态类型、高效的并发处理、自动垃圾回收等诸多优势,语法简洁又不失丰富性。从数据类型、赋值操作、循环结构到函数特性、垃圾回收机制、并发与错误处理等各个方面,都展现出独特的设计理念。无论是初学者还是有经验的开发者,都能在 Go 语言中找到适合的应用场景和开发乐趣,它为软件开发领域提供了一个高效、可靠的开发选择。