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

90 阅读8分钟

开发环境配置

Go语言运行环境(Windows)

访问 go.dev/ ,点击 Download ,选择对应平台安装包,安装即可。

当然,上面的网站需要魔法,如果无法访问上面的网址,可以改为访问 studygolang.com/dl 下载安装

studygolang.com/dl同样有go语言的图书、开源博客、项目指南、官方文档等资源,可以常去看看

Windows环境下,go安装包安装成功后,会自动将go的bin目录添加到Path下,所以不需要再向Path环境变量中添加go的地址

同时我们需要修改GOPATH变量,GOPATH是保存go代码和第三方依赖包(src)、编译时生成的中间文件(pkg)、编译后生成的可执行文件(bin)的地方。

image-20241108003950154.png

Go语言运行环境(Linux)

运行下列命令

# 下载Go语言二进制包,dl.gogle.com需要魔法,可以使用镜像
wget https://dl.google.com/go/{tar_version}
 
# 解压缩到/usr/local目录
sudo tar -C /usr/local -xzf {tar_version}
 
# 设置环境变量
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.profile
source ~/.profile
 
# 验证安装
go version

image-20241108005807343.png

IDE

选择Goland,去Jetbrains官网,下载安装即可。

在Goland中可以设置项目地址,GOROOT(Go的安装路径)以及一些运行参数(比较重要的是GOPROXY,可以使用镜像资源下载第三方依赖包)

image-20241108004844587.png

镜像资源

第三方依赖包镜像资源

基本语法

这里简单整理 Go 的基础语法,可以速查。 一些不明白的可以查阅Go语言圣经

一、Hello World

Go语言输出Hello World实现如下

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

Go是一门编译型语言,Go语言的工具链将源代码及其依赖转换成计算机的机器指令(即静态编译)。通过go run 文件名命令可以运行Go 代码。通常我们使用go build 文件名来构建Go代码的二进制文件。 Go语言的代码通过包(package)组织,类似于其他语言的库或模块,package main表示该文件属于main包。main包定义了程序的主体,其中main函数就是程序的入口。

二、变量类型

  • 布尔型:true/false
  • 整形:uint(8/16/32/64)/int(8/16/32/64)
  • 浮点型:float32/float64/complex64/complex128
  • 其他类型: byte(类似 uint8), int/uint(32 或 64 位), uintptr(无符号整型,用于存放指针)
  • 字符串:默认为 UTF-8编码
  • 派生类型:指针/数组/函数/struct/slice/interface/map

三、变量与常量

Go语言中,变量是强类型的,我们在声明变量时一定要指定变量类型。 定义变量有几种方式 第一种是使用var定义变量,通常来说,Go语言可以依据变量的初始值来推断出变量类型,如下

var hello = "Hello world"  // 字符串
var num = 1 			   // 整形
var isTrue = true		   // 布尔

我们还可以使用:=运算符,作用类似于上面,如

hello := "Hello world"
num := 1
isTrue := true

如果需要强调类型,可以写作下面的形式

var hello string = "Hello world"
var num int32 = 1 
var isTrue bool = true	

如果不初始化变量,变量的值是什么

  • 字符串默认值为空
  • 整型、浮点型默认值为 0
  • 布尔型默认值为 false
  • 指针、channel、func、接口都为 nil
  • 数组默认为 []
  • 字典默认为 map[]

如果需要定义常量,需要添加关键字const,如

const constHello = "Hello world"

四、条件

Go中的条件语句主要包括if-else以及switch,因为比较类似于其他语言的形式,直接使用代码说明。

// if-else
func main() {
   a := 1
   if a >= 0 {
      fmt.Println("a is a non-negative number")
   } else {
      fmt.Println("a is a negative number")
   }
   
   b := 10
   if b > 0 {
      fmt.Println("b is a positive number")
   } else if b == 0 {
      fmt.Println("b is 0")
   } else {
      fmt.Println("b is a negative number")
   }
   
// switch, Go种switch不需要加break
   c := 10
   switch c % 3{
      case 0: fmt.Println("c 能被3整除")
      case 1: fmt.Println("c 被3除余1")
      case 2: fmt.Println("c 被3除余2")
   }
   // 另一种写法,可以当作一串if-else语句
   switch {
      case c % 3 == 0: fmt.Println("c 能被3整除")
      case c % 3 == 1: fmt.Println("c 被3除余1")
      case c % 3 == 2: fmt.Println("c 被3除余2")
   }
   
}

五、循环

Go语言中表示循环的关键字仅有for一种(这正体现了Go的Less is more,当然我们可以利用for实现各种不同形式的循环(本质是一样的)。

for i := 0; i <= 3; i++ {
    fmt.Println(i)
}
//类似于while
i = 0
for i <= 3 {
   fmt.Println(i)
   i++
}
// 死循环
i = 0
for {
   fmt.Println(i)
   i ++
   if i > 3 {
      break
   }
}

六、一些重要的数据类型

1. 数组

数组定义方式如下

var testArray [3]int

for i := 0; i < 3; i++ {
   testArray[i] = i
}

//第二种方式
arrayA := [3]int{1, 2, 3}
arrayB := [...]int{1 , 2, 3}
2Darray := [2][2]int{
   {1, 2}
   {3, 4}
}

Go 中的数组是固定长度的,一旦创建了就不允许改变,空余位置用 0 填补并且不允许越界。一般来说数组使用不是很方便。

2.slice

固定长度的数组不是很方便,所以我们一般都用切片来操作 slice结构体的底层定义如下

type slice struct {
    array unsafe.Pointer // 指向数组的指针
    len int // 切片中的元素数量
    cap int // array 数组的总容量
}

定义slice,一般使用make进行定义,第一个参数表示类型,第二个表示切片长度,第三个表示容积(可省略)

testSlice := make([]int, 2)
testSlice[0] = 1
testSlice[1] = 0

添加元素,使用append方法(因为我们通常不知道返回的slice是否与原slice的指向同一个引用,通常会将插入元素后的slice重新赋值给原slice)

testSlice = append(testSlice, 3, 4)

获取切片大小,使用len方法

len(testSlice)

拷贝

//1
anoSlice := testSlice
//2
another := make([]int, len(testSlice))
copy(another, testSlice)

第一种方法只是将testSlice的引用传递给了anoSlice anoSlice和testSlice实质上指向的是同一个slice 第二种方法使用copy方法 another和testSlice指向的是不同的slice,只是里面内容一样

实质上,切片底层是数组。当空间不够时,切片会将自身复制到一个更大的数组上去。因为切片扩容操作涉及到拷贝,通常在实际使用中为了减小拷贝的开销,会将切片初始值设定的较大。

选取切片部分(类似于Python的List中的操作,但不支持负数索引)

testSlice[1:]
testSlice[:2]
testSlice[1:3]

3. 字典

字典即由一系列键值对组成 定义与添加键值对 Go语言中的range可以同时遍历字典的键和值,当不需要某一部分时可以用_代替

m := make(map[string]int)
m["Hello"] = 1
m["World"] = 2

m1 := map[string]int{"Hello": 1, "world": 2}

for k, v := range m {
    fmt.Println(k, v)
}
for _, num := range m1 {
    fmt.Println(v)
}

删除键值对使用delete方法

delete(m, "Hello")

七、函数

1.函数定义

在Go语言中,使用func关键字声明一个函数,函数声明的语法与其他语言略有差异。Go语言中函数也是由函数名、参数列表、返回值组成。 Go语言函数声明的通用格式是func funcName(args) (return_type)。 如

func add(num1 int, num2 int) int {
    return num1 + num2
}

需要强调的是,Go语言中的参数传递只有值传递,但是具体传的值,可以分为引用类型(指针/map/slice等)和非引用类型(int/string/struct/array等)。当我们传入的参数是非引用类型时,我们修改的参数值不会反映到原变量上去,如果传入的是引用类型,修改变量的内容会导致原变量发生改变(因为参数与原变量指向同一个引用)

2.函数调用

Go语言中函数的调用也类似于其他语言。

3.错误处理

通常来说,Go函数的错误处理很简单,只需要添加一个类型为Error的返回值即可。 比如

func greeting(name string) (string, error) {
    if name == "" {
        return name, errors.New("Name is nil")
    }
    Words := fmt.Sprintf("Hello,%v", name)
    return Words, nil
}
  • 我们添加了一个返回值类型error,它用于接收程序运行的错误信息。
  • 当name为空时,我们返回错误信息
  • 如果允许正常,我们的errornil,通常来说,nil也是程序运行正常的标志
  • 在调用函数时,只需要用一个变量接收error,并对其进行判断、处理即可。

八、结构体

面向对象是一个重要的思想,Go语言中可以使用结构体实现面向对象。 我们可以使用struct关键字定义类名、成员变量等。

type O struct{
    int
}
type T struct {
    a int
    b O
}
var i1 T	// 值类型
var i2 new(T)	// 引用类型

在面向对象中,一个对象不仅要包括成员变量,还需要包括对象的方法。Go语言中通过在函数前添加声明,来将某个函数绑定到某个结构体上。 那么函数的定义将变为 func (structName structType) funcName(args) (return_type) 即在函数名前面添加参数名称和需要绑定的结构体即可。 需要注意的是,我们传入的可以是struct的值,也可以传入struct的指针。struct是非引用类型,当我们需要直接修改struct的成员变量的值,我们需要传入指针。 传入的struct和其对应的方法必须在同一个包内。