一篇文章学会golang语法,golang简明教程快速入门
lipiwang 2025-06-13 14:44 6 浏览 0 评论
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。 —— Go - wikipedia.org
1 Go 安装
最新版本下载地址官方下载 https://golang.org,https://go.dev/
当前是 1.19.3。如无法访问,可以在 https://golang.google.cn/ 下载
使用 Linux,可以用如下方式快速安装。
|
从 Go 1.11 版本开始,Go 提供了 Go Modules 的机制,推荐设置以下环境变量,第三方包的下载将通过国内镜像,避免出现官方网址被屏蔽的问题。
|
或在 ~/.profile 中设置环境变量
|
2 Hello World
新建一个文件 main.go,写入
|
执行go run main.go 或 go run .,将会输出
|
如果强制启用了 Go Modules 机制,即环境变量中设置了 GO111MODULE=on,则需要先初始化模块 go mod init hello
否则会报错误:go: cannot find main module; see ‘go help modules’
我们的第一个 Go 程序就完成了,接下来我们逐行来解读这个程序:
- package main:声明了 main.go 所在的包,Go 语言中使用包来组织代码。一般一个文件夹即一个包,包内可以暴露类型或方法供其他包使用。
- import “fmt”:fmt 是 Go 语言的一个标准库/包,用来处理标准输入输出。
- func main:main 函数是整个程序的入口,main 函数所在的包名也必须为 main。
- fmt.Println(“Hello World!”):调用 fmt 包的 Println 方法,打印出 “Hello World!”
go run main.go,其实是 2 步:
- go build main.go:编译成二进制可执行程序
- ./main:执行该程序
3 变量与内置数据类型
3.1 变量(Variable)
Go 语言是静态类型的,变量声明时必须明确变量的类型。Go 语言与其他语言显著不同的一个地方在于,Go 语言的类型在变量后面。比如 java 中,声明一个整体一般写成 int a = 1,在 Go 语言中,需要这么写:
|
var a = 1,因为 1 是 int 类型的,所以赋值时,a 自动被确定为 int 类型,所以类型名可以省略不写,这种方式还有一种更简单的表达:
|
3.2 简单类型
空值:nil
整型类型: int(取决于操作系统), int8, int16, int32, int64, uint8, uint16, …
浮点数类型:float32, float64
字节类型:byte (等价于uint8)
字符串类型:string
布尔值类型:boolean,(true 或 false)
|
3.3 字符串
在 Go 语言中,字符串使用 UTF8 编码,UTF8 的好处在于,如果基本是英文,每个字符占 1 byte,和 ASCII 编码是一样的,非常节省空间,如果是中文,一般占3字节。包含中文的字符串的处理方式与纯 ASCII 码构成的字符串有点区别。
我们看下面的例子:
|
- reflect.TypeOf().Kind() 可以知道某个变量的类型,我们可以看到,字符串是以 byte 数组形式保存的,类型是 uint8,占1个 byte,打印时需要用 string 进行类型转换,否则打印的是编码值。
- 因为字符串是以 byte 数组的形式存储的,所以,str2[2] 的值并不等于语。str2 的长度 len(str2) 也不是 4,而是 8( Go 占 2 byte,语言占 6 byte)。
正确的处理方式是将 string 转为 rune 数组
|
转换成 []rune 类型后,字符串中的每个字符,无论占多少个字节都用 int32 来表示,因而可以正确处理中文。
3.4 数组(array)与切片(slice)
声明数组
|
声明是初始化
|
使用 [] 索引/修改数组
|
数组的长度不能改变,如果想拼接2个数组,或是获取子数组,需要使用切片。切片是数组的抽象。 切片使用数组作为底层结构。切片包含三个组件:容量,长度和指向底层数组的指针,切片可以随时进行扩展
声明切片:
|
使用切片:
|
- 声明切片时可以为切片设置容量大小,为切片预分配空间。在实际使用的过程中,如果容量不够,切片容量会自动扩展。
- sub2... 是切片解构的写法,将切片解构为 N 个独立的元素。
3.5 字典(键值对,map)
map 类似于 java 的 HashMap,Python的字典(dict),是一种存储键值对(Key-Value)的数据解构。使用方式和其他语言几乎没有区别。
|
3.6 指针(pointer)
指针即某个值的地址,类型定义时使用符号*,对一个已经存在的变量,使用 & 获取该变量的地址。
|
一般来说,指针通常在函数传递参数,或者给某个类型定义新的方法时使用。Go 语言中,参数是按值传递的,如果不使用指针,函数内部将会拷贝一份参数的副本,对参数的修改并不会影响到外部变量的值。如果参数使用指针,对参数的传递将会影响到外部变量。
例如:
|
4 流程控制(if, for, switch)
4.1 条件语句 if else
|
4.2 switch
|
- 在这里,使用了type 关键字定义了一个新的类型 Gender。
- 使用 const 定义了 MALE 和 FEMALE 2 个常量,Go 语言中没有枚举(enum)的概念,一般可以用常量的方式来模拟枚举。
- 和其他语言不同的地方在于,Go 语言的 switch 不需要 break,匹配到某个 case,执行完该 case 定义的行为后,默认不会继续往下执行。如果需要继续往下执行,需要使用 fallthrough,例如:
|
4.3 for 循环
一个简单的累加的例子,break 和 continue 的用法与其他语言没有区别。
|
对数组(arr)、切片(slice)、字典(map) 使用 for range 遍历:
|
5 函数(functions)
5.1 参数与返回值
一个典型的函数定义如下,使用关键字 func,参数可以有多个,返回值也支持有多个。特别地,package main 中的func main() 约定为可执行程序的入口。
|
例如,实现2个数的加法(一个返回值)和除法(多个返回值):
|
也可以给返回值命名,简化 return,例如 add 函数可以改写为
|
5.2 错误处理(error handling)
如果函数实现过程中,如果出现不能处理的错误,可以返回给调用者处理。比如我们调用标准库函数os.Open读取文件,os.Open 有2个返回值,第一个是 *File,第二个是 error, 如果调用成功,error 的值是 nil,如果调用失败,例如文件不存在,我们可以通过 error 知道具体的错误信息。
|
可以通过 errorw.New 返回自定义的错误
|
error 往往是能预知的错误,但是也可能出现一些不可预知的错误,例如数组越界,这种错误可能会导致程序非正常退出,在 Go 语言中称之为 panic。
|
|
在 Python、Java 等语言中有 try...catch 机制,在 try 中捕获各种类型的异常,在 catch 中定义异常处理的行为。Go 语言也提供了类似的机制 defer 和 recover。
|
|
- 在 get 函数中,使用 defer 定义了异常处理的函数,在协程退出前,会执行完 defer 挂载的任务。因此如果触发了 panic,控制权就交给了 defer。
- 在 defer 的处理逻辑中,使用 recover,使程序恢复正常,并且将返回值设置为 -1,在这里也可以不处理返回值,如果不处理返回值,返回值将被置为默认值 0。
6 结构体,方法和接口
6.1 结构体(struct) 和方法(methods)
结构体类似于其他语言中的 class,可以在结构体中定义多个字段,为结构体实现方法,实例化等。接下来我们定义一个结构体 Student,并为 Student 添加 name,age 字段,并实现 hello() 方法。
|
- 使用 Student{field: value, ...}的形式创建 Student 的实例,字段不需要每个都赋值,没有显性赋值的变量将被赋予默认值,例如 age 将被赋予默认值 0。
- 实现方法与实现函数的区别在于,func 和函数名hello 之间,加上该方法对应的实例名 stu 及其类型 *Student,可以通过实例名访问该实例的字段name和其他方法了。
- 调用方法通过 实例名.方法名(参数) 的方式。
除此之外,还可以使用 new 实例化:
|
6.2 接口(interfaces)
一般而言,接口定义了一组方法的集合,接口不能被实例化,一个类型可以实现多个接口。
举一个简单的例子,定义一个接口 Person和对应的方法 getName() 和 getAge():
|
- Go 语言中,并不需要显式地声明实现了哪一个接口,只需要直接实现该接口对应的方法即可。
- 实例化 Student后,强制类型转换为接口类型 Person。
在上面的例子中,我们在 main 函数中尝试将 Student 实例类型转换为 Person,如果 Student 没有完全实现 Person 的方法,比如我们将 (*Student).getName() 删掉,编译时会出现如下报错信息。
|
但是删除 (*Worker).getName() 程序并不会报错,因为我们并没有在 main 函数中使用。这种情况下我们如何确保某个类型实现了某个接口的所有方法呢?一般可以使用下面的方法进行检测,如果实现不完整,编译期将会报错。
|
- 将空值 nil 转换为 *Student 类型,再转换为 Person 接口,如果转换失败,说明 Student 并没有实现 Person 接口的所有方法。
- Worker 同上。
实例可以强制类型转换为接口,接口也可以强制类型转换为实例。
|
6.3 空接口
如果定义了一个没有任何方法的空接口,那么这个接口可以表示任意类型。例如
|
7 并发编程(goroutine)
7.1 sync
Go 语言提供了 sync 和 channel 两种方式支持协程(goroutine)的并发。
例如我们希望并发下载 N 个资源,多个并发协程之间不需要通信,那么就可以使用 sync.WaitGroup,等待所有并发协程执行结束。
|
- wg.Add(1):为 wg 添加一个计数,wg.Done(),减去一个计数。
- go download():启动新的协程并发执行 download 函数。
- wg.Wait():等待所有的协程执行结束。
|
可以看到串行需要 3s 的下载操作,并发后,只需要 1s。
7.2 channel
|
使用 channel 信道,可以在协程之间传递消息。阻塞等待并发协程返回消息。
|
8 单元测试(unit test)
假设我们希望测试 package main 下 calc.go 中的函数,要只需要新建 calc_test.go 文件,在calc_test.go中新建测试用例即可。
|
|
运行 go test,将自动运行当前 package 下的所有测试用例,如果需要查看详细的信息,可以添加-v参数。
|
9 包(Package)和模块(Modules)
9.1 Package
一般来说,一个文件夹可以作为 package,同一个 package 内部变量、类型、方法等定义可以相互看到。
比如我们新建一个文件 calc.go, main.go 平级,分别定义 add 和 main 方法。
|
|
运行 go run main.go,会报错,add 未定义:
|
因为 go run main.go 仅编译 main.go 一个文件,所以命令需要换成
|
或
|
Go 语言也有 Public 和 Private 的概念,粒度是包。如果类型/接口/方法/函数/字段的首字母大写,则是 Public 的,对其他 package 可见,如果首字母小写,则是 Private 的,对其他 package 不可见。
9.2 Modules
Go Modules 是 Go 1.11 版本之后引入的,Go 1.11 之前使用 $GOPATH 机制。Go Modules 可以算作是较为完善的包管理工具。同时支持代理,国内也能享受高速的第三方包镜像服务。接下来简单介绍 go mod 的使用。Go Modules 在 1.13 版本仍是可选使用的,环境变量 GO111MODULE 的值默认为 AUTO,强制使用 Go Modules 进行依赖管理,可以将 GO111MODULE 设置为 ON。
在一个空文件夹下,初始化一个 Module
|
此时,在当前文件夹下生成了go.mod,这个文件记录当前模块的模块名以及所有依赖包的版本。
接着,我们在当前目录下新建文件 main.go,添加如下代码:
|
运行 go run .,将会自动触发第三方包 rsc.io/quote的下载,具体的版本信息也记录在了go.mod中:
|
我们在当前目录,添加一个子 package calc,代码目录如下:
|
在 calc.go 中写入
|
在 package main 中如何使用 package cal 中的 Add 函数呢?import 模块名/子目录名 即可,修改后的 main 函数如下:
|
|
附 参考
- golang 官方文档 - golang.org
- goproxy.cn 文档 - github.com
- Go Modules - github.com
专题: Go 简明教程
相关推荐
- Go语言图书管理RESTful API开发实战
-
Go(Golang)是最近流行起来,且相对较新的编程语言。它小而稳定,使用和学习简单,速度快,经过编译(原生代码),并大量用于云工具和服务(Docker、Kubernetes...)。考虑到它所带来的...
- 轻松搞定Golang 中的内存管理(golang设置内存大小)
-
除非您正在对服务进行原型设计,否则您可能会关心应用程序的内存使用情况。内存占用更小,基础设施成本降低,扩展变得更容易/延迟。尽管Go以不消耗大量内存而闻名,但仍有一些方法可以进一步减少消耗。其中一...
- golang实现deepseek 聊天功能(golang deepcopy)
-
在搭建完deepseek环境后在docker内部署deepseekrag环境,我们可以用golang实现聊天功能。在实现这个功能之前,我们先了解下提示词工程(prompt)。大模型虽然知道的东西多...
- golang slice的扩容机制(golang设置内存大小)
-
在Go语言中,切片(slice)是一种动态数组,其长度可以在运行时改变。当向切片中添加元素时,如果切片的容量不足以容纳新元素,就会触发扩容机制。下面详细介绍Go语言切片的扩容机制。扩容触发条件...
- Etcd服务注册与发现封装实现--golang
-
服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...
- 嘿,轻松获取区间内所有日期的Golang小技巧!
-
在Go语言中,获取两个日期之间的所有日期可以手动实现一个函数来完成。以下是一个示例函数,它会返回一个日期切片,包含从开始日期到结束日期(包括这两个日期)的所有日期:packagemainimpo...
- 仓颉、Java、Golang性能测试——数组扩容
-
版本信息仓颉版本0.53.18Golang版本1.22.8Java版本corretto-1.8.0_452源码仓颉packagecangjie_testimportstd.collect...
- Golang 58个坑 – 中级篇:36-51(golang cef)
-
36.关闭HTTP的响应体37.关闭HTTP连接38.将JSON中的数字解码为interface类型39.struct、array、slice和map的值比较40.从panic...
- 一篇文章学会golang语法,golang简明教程快速入门
-
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。——Go-wikipedia.org1Go安装最新版本下载地址官方下载https...
- 运维大神如何使用 Golang 日志监控应用程序
-
你是如何使用Golang日志监控你的应用程序的呢?Golang没有异常,只有错误。因此你的第一印象可能就是开发Golang日志策略并不是一件简单的事情。不支持异常事实上并不是什么问题,异常在...
- Golang操作elasticsearch(golang操作word)
-
简介开源的Elasticsearch是目前全文搜索引擎的首选,很多日志都是放到elasticsearch里面,然后再根据具体的需求进行分析。目前我们的运维系统是使用golang开发的,需要定时到e...
- 一文带你看懂Golang最新特性(golang x)
-
作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...
- Golang 最常用函数(备用查询)(golang函数和方法)
-
hello.gopackagemainimport"fmt"funcmain(){fmt.Println("Hello,world!")}直...
- Golang:将日志以Json格式输出到Kafka
-
在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...
- 如何从 PHP 过渡到 Golang?(php转go需要多久)
-
我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)