Go学习之路

Go学习之路

环境安装

Windows上安装 Go 环境并配置环境变量 (超详细教程)_go环境变量配置 windows-CSDN博客

【2024最新】GoLand最新版本免费使用教程附带安装包!超详细_哔哩哔哩_bilibili

1
2
3
GoLand 破解网盘
链接:https://tool.nineya.com/s/1iduahtej
提取码:q23b

语法学习

https://chat.deepseek.com/a/chat/s/f93445e7-f6fc-42e0-824b-2a76b9ee7c17

标准结构

1
2
3
4
5
6
7
package main  // 每个Go文件必须属于一个包

import "fmt" // 导入标准库的fmt包

func main() { // 主函数,程序入口
fmt.Println("Hello, World!") // 打印语句,不需要分号
}

变量声明

type:

  • int- 存储整数(整数),例如 123 或 -123
  • float32- 存储浮点数,带小数,例如 19.99 或 -19.99
  • string - 存储文本,例如”Hello World”。 字符串值用双引号括起来
  • bool- 存储具有两种状态的值:真或假
1
var variablename type = value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var name string = "Go"

// 以下两种类型均由推断得出
var count = 10
// 短变量声明(只能在函数内使用)
count := 5

const
(
pi = 3.14
pi1 = 3.15
)

const // 该方法可以用于定义枚举
(
pi = iota // 赋值为0
pi1 // pi1自动赋值为1
)

var x,y,z = 1,2,3
g,h:= "g","h"

TIP:var count = 10count := 5的区别是什么

第一个可以声明在函数之外、第二个只能声明在函数内部使用,而且必须初始化

Pair对

static type:基本数据类型

concrete type:interface指向的具体数据类型

一种变量的type是只能是以上两者的一个

1

image-20250803222056312

pair类型会在赋值之后连续传递

在这里allType万能类型的type其实是concrete type,并且是指向a的type的,为string

image-20250803222435335

子父接口继承,正是因为pair的机制,使其支持自下而上转换

复合类型

数组:

1
2
var arr [3]int = [3]int{1,2,3}
arr1 := [3]int{1,2,3}

动态数组:

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

Map映射:

1
2
m := map[string]int{"one":1,"two":2}
value, exists := m["three"] // 检查键是否存在 value:0,exists:false

结构体

type struct_name struct {
member1 datatype;
member2 datatype;
member3 datatype;

}

1
2
3
4
type Person struct{
Name string
Age int
}
1
2
3
4
func main(){
p :=Person{Name:"xiaoming",Age:123}
fmt.Println(p.Name)
}
1
2
3
4
5
func main(){
var p Person
p.Name = "xiaoming"
fmt.Println(p.Name)
}

以下包含了结构体方法定义、结构体修改的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type Rectangle struct {
Width, Height float64
}

// 方法(值接收者):当你调用这个方法时,Go 会将 Rectangle 的一个副本传给方法,方法内部操作的是这个副本,不会影响原始对象。
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}


// 方法(指针接收者,可修改结构体):方法接收的是原结构体的内存地址(指针)​,因此通过这个指针可以直接修改原结构体的字段值。
func (r *Rectangle) Scale(factor float64) {
// 对对象内部的属性进行修改
r.Width *= factor
r.Height *= factor
}

func main(){
// 使用
rect := Rectangle{Width: 3, Height: 4}
fmt.Println(rect.Area()) // 12
rect.Scale(2)
fmt.Println(rect.Area()) // 48

}

继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import "fmt"

type Human struct {
name string
sex int
}

func (h *Human) Detail() {
fmt.Println("name:", h.name, "sex:", h.sex)
}
func (h *Human) Sex(s int) {
h.sex = s
}

type SuperMan struct {
Human // 继承的语法
level int
}

func (sh SuperMan) Fly() {
fmt.Println("superMan fly")
}

func main() {
h := Human{name: "tiancai", sex: 1}
h.Sex(0)
sh := SuperMan{Human{name: "spiderMan", sex: 1}, 10}
h.Detail()
sh.Detail() // 调用子类方法
sh.Fly()
}
1
2
3
name: tiancai sex: 0
name: spiderMan sex: 1
superMan fly

接口

type interface_name interface{

function_name type

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Rectangle struct {
Width, Height float64
}

// 方法(值接收者)
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}

type Shape interface{
Area() float64;
}
func printx(s Shape){
fmt.Println(s.Area())
}

// Rectangle自动实现Shape接口(无需显式声明)
rect := Rectangle{Width: 3, Height: 4}
printArea(rect) // 12

空接口:

interface{},Go中所有的变量都继承于这个,可以理解为java的Object类,使用该关键字可以在方法中引入不限制类型的变量

他同时提供了类型断言的方法,来判断类型:arg.(string)判断是否是字符串类型

1
2
3
4
5
6
7
8
9
10
func typeJudge(i interface{}) {
switch i.(type) {
case Human: // struct类型为Human的情况
fmt.Println("Human")
case SuperMan:
fmt.Println("SuperMan")
default:
fmt.Println("unknow")
}
}

函数定义

无返回值:

func FunctionName(param1 type, param2 type) {
// 要执行的代码
}

1
2
3
func print1(name string){
fmt.Println("print:",name);
}

有返回值:

func FunctionName(param1 type, param2 type) type {
// 要执行的代码
return output
}

1
2
3
func add(i int)int{
return i+1
}

多返回值:

1
2
3
4
5
6
7
8
9
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}

i,_:=divide(1,0)
print1(i) // 0

可变参数:

这里的_代表当前元素的索引不存储,相当于一个空位置

1
2
3
4
5
6
7
8
9
10
11
12
func main(){
print1(sum(1,2,3))
}

func sum(nums ...int)int{
total :=0
for _,num := range nums{
total +=num
}
return total
}

函数作为参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 函数作为参数
func main(){
i :=apply(op,1,2)
print1(i) // 3
}

// 函数作为参数
func apply(op func(int, int) int, a, b int) int {
return op(a, b)
}
func op(a,b int)int{
return a+b
}

递归调用:

1
2
3
4
5
6
7
func test(count int) int{
if(count >= 10){
return 0
}
fmt.Println(count)
return test(count+1)
}

控制结构

条件语句:

相比java就是省去了括号

1
2
3
4
5
6
7
if count>0{
return count
}else if count == 0{
return 0
}else{
return -1
}
1
2
3
4
5
6
7
8
9
10
// 初始赋值if
if v:=compute();v>0{
fmt.Println(v)
}else{
fmt.Println(0)
} // print: 0

func compute() int{
return 0
}

循环语句:

1
2
3
4
5
6
7
8
for i:=1;i<=5;i++{
print1(i)
}

for{
print1("123") // 无限循环
// break
}

while循环:

1
2
3
4
5
v :=5
for v>0{
print1(v)
v--
}

range循环:

类似于javaforeach

1
2
3
4
nums := []int{1, 2, 3}
for i,v := range nums{
fmt.Printf("index:%d,value:%d\n",i,v)
}
1
2
3
index:0,value:1
index:1,value:2
index:2,value:3

指针

image-20250802230503192


如果*p=a,那么p=&a

*p表示的是p地址指向的内存,而&a表示的是a内存的地址

image-20250802231226405

值交换:

1
2
3
4
5
func Exchange(a, b *int) {
a1 := *a
*a = *b
*b = a1
}

其他关键字

defer

在程序结束之后进行操作

defer晚于return执行

多个defer最下面的先执行

image-20250802233112570

项目结构

go执行流程

image-20250801214513049

Go Moduels

结构:

image-20250801223238424

指令:

命令 作用 类比 Java
go mod init [module-path] 初始化一个新的 Go 模块,生成 go.mod 文件 类似于创建 Maven 项目 / 初始化 pom.xml
go get [package]@[version] 手动获取某个依赖包(可指定版本) 类似于在 pom.xml 添加依赖,或使用 mvn install
go mod tidy 清理未使用的依赖,添加缺失的依赖 类似于 Maven 的依赖分析,清理未使用的 jar
go list -m all 查看当前模块依赖的所有第三方包 类似于查看 Maven 依赖树
go mod vendor(可选) 将依赖复制到项目下的 vendor 目录(类似传统打包方式) 类似 Maven 的 mvn dependency:copy-dependencies 到 lib/
go build / go run 编译或运行程序,自动解析依赖

如何手动引入依赖?

直接在代码里 import "xxx",然后运行 go run/main/build,Go 会自动下载依赖

包工作流程

初始化modules:

1
go mod init github.com/fansea0/my-go-project # github.com/fansea0/my-go-project 是模块名称

创建目录结构:

1
2
3
4
5
6
go_modules_test/
├── go.mod # 保存该模块外部依赖信息(类似于外链),外部依赖通常会保存在gopath的lib包下
├── main.go # 程序主入口,包名为main
└── lib/
├── lib1.go # 模块子包的类,lib1与lib2的package需要一致,同一个子包的类型可以直接调用
└── lib2.go
1
2
3
4
5
6
7
8
9
10
11
// go.mod
module github.com/fansea0/my-go-project

go 1.24.5

require rsc.io/quote v0.0.0-20190312145912-0406d7298882

require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/sampler v1.3.0 // indirect
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// main.go
package main

import (
"fmt"
"rsc.io/quote" // 这是一个 Go 官方示例的第三方包
// 导入lib包
"github.com/fansea0/my-go-project/lib"
)

func main() {
fmt.Println(quote.Hello())
lib.Test()
lib.Test2()
}
1
2
3
4
5
6
7
8
9
10
11
12
// lib1.go
package lib

import "fmt"

func init() { // 初始化方法
fmt.Println("lib1 init")
}

func Test() { // 只有首字母为大写的方法可以供外部调用
fmt.Println("lib1 test")
}
1
2
3
4
5
6
// lib2.go
package lib

func Test2() {
Test()
}
1
2
3
4
5
// 输出
lib1 init
Hello, world.
lib1 test
lib1 test

匿名包:

包引入之后必须要使用,否则不能通过编译,这里提供匿名包,允许包不使用,但是依然会执行包的init方法

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"rsc.io/quote" // 这是一个 Go 官方示例的第三方包
// 匿名包
_ "github.com/fansea0/my-go-project/lib"
)

func main() {
fmt.Println(quote.Hello())

}
1
2
lib1 init
Hello, world.

GoPATH是什么

GOPATH 是 Go 语言在 1.11 版本之前 管理项目、依赖和代码工作空间的核心机制

用于依赖管理,提供打包功能的工作空间集成,在go Modules出现之后被淘汰

并发编程