文章目录
go教程go 简介go 安装go 常用命令build 和 run 命令fmt 和 doc 命令install 命令env 命令get 命令go package包的基本概念包导入包管理工具GOROOT 和GOPATH区别Vendor 机制引入Go Modules启用 go module 功能使用 go module 功能go语法变量定义普通变量结构体和接口字符串数组切片map链表list流程控制循环函数异常处理go教程
go 简介
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。
Go是从末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于11月开源,在早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。
相关网站:
go官网:/pkg/
go依赖包搜索:/
go 安装
安装包下载地址为:/dl/。
window安装目录默认为:c:/go,bin目录自动指向bin目录。
linux解压tgz包,将bin目录添加到PATH变量中,假设go解压在/opt/go目录下
cat << 'EOF' >> ~/.bash_profilePATH=$PATH:/opt/go/binexport PATHEOF
测试go是否正常安装
C:\Users\GVT>go versiongo version go1.14.2 windows/amd64
go 常用命令
直接在终端中输入 go help 即可显示所有的 go 命令以及相应命令功能简介,主要有下面这些:
build: 编译包和依赖clean: 移除对象文件doc: 显示包或者符号的文档env: 打印go的环境信息bug: 启动错误报告fix: 运行go tool fixfmt: 运行gofmt进行格式化generate: 从processing source生成go文件get: 下载并安装包和依赖install: 编译并安装包和依赖list: 列出包run: 编译并运行go程序test: 运行测试tool: 运行go提供的工具version: 显示go的版本vet: 运行go tool vet
命令的使用方式为: go command [args], 除此之外,可以使用go help 来显示指定命令的更多帮助信息。
在运行 go help 时,不仅仅打印了这些命令的基本信息,还给出了一些概念的帮助信息:
c: Go和c的相互调用buildmode: 构建模式的描述filetype: 文件类型gopath: GOPATH环境变量environment: 环境变量importpath: 导入路径语法packages: 包列表的描述testflag: 测试符号描述testfunc: 测试函数描述
同样使用 go help 来查看这些概念的的信息。
build 和 run 命令
就像其他静态类型语言一样,要执行 go 程序,需要先编译,然后在执行产生的可执行文件。go build 命令就是用来编译 go程序生成可执行文件的。但并不是所以的 go 程序都可以编译生成可执行文件的, 要生成可执行文件,go程序需要满足两个条件:
该go程序需要属于main包在main包中必须还得包含main函数
也就是说go程序的入口就是 main.main, 即main包下的main函数,例子(hello.go):
cat <<EOF > hello.gopackage mainimport "fmt"func main(){fmt.Println("Hello World")}EOF
编译hello.go,然后运行可执行程序:
go build hello.go
当前目录下生成了hello.exe,运行
GVT@DESKTOP-V14R68B MINGW64 ~/go$ ./hello.exeHello World
而 go run 命令可以将上面两步并为一步执行(不会产生中间文件)。
$ go run hello.goHello World!
上面两个命令都是在开发中非常常用的。
此外 go clean 命令,可以用于将清除产生的可执行程序:
$ go clean # 不加参数,可以删除当前目录下的所有可执行文件$ go clean sourcefile.go # 会删除对应的可执行文件
fmt 和 doc 命令
go 语言有一个褒贬不一的特性,就是对格式的要求很严格,我是很喜欢这个特性的,因为可以保持代码的清晰一致,编译组合开发,并且go还提供了一个非常强大的工具来格式化代码,它就是 go fmt sourcefile.go, 不过通常其实不需要我们手动调用,各种编辑器都可以帮助我们自动完成格式化。
go doc 命令可以方便我们快速查看包文档,go doc package 命令将会在终端中打印出指定 package 的文档。
如查看fmt文档
go doc fmt
另外有一个与 go doc 命令相关的命令是 godoc, 可以通过它启动我们自己的文档服务器:
godoc -http=:8080
然后我们就可与在浏览器localhost:8080中查看go文档了
godoc默认不带可执行程序,生成可执行程序步骤
git clone /golang/tools /x/tools go安装目录/src新建\x\tools目录 拷贝源代码到该目录cd C:\Go\src\\x\tools\godocgo build /x/tools/cmd/godocgo install /x/tools/cmd/godoc 自动拷贝到bin目录
install 命令
用来编译和安装go程序,我们可以将它与 build 命令对比:
生成的可执行文件路径 工作目录下的bin目录下 当前目录下
可执行文件的名字 与源码所在目录同名 默认与源程序同名,可以使用-o选项指定
依赖 将依赖的包放到工作目录下的pkg文件夹下 -
env 命令
查看所有环境变量
go envgo env | grep GOROOT
修改环境变量(设置中国区代理或者阿里云代理:/goproxy/)
go env -w GOPROXY=
get 命令
go get 命令可以借助代码管理工具通过远程拉取或更新代码包及其依赖包,并自动完成编译和安装。整个过程就像安装一个 App 一样简单。
这个命令可以动态获取远程代码包,目前支持的有 BitBucket、GitHub、Google Code 和 Launchpad。在使用 go get 命令前,需要安装与远程包匹配的代码管理工具,如 Git、SVN、HG 等,参数中需要提供一个包名。
这个命令在内部实际上分成了两步操作:第一步是下载源码包,第二步是执行 go install。下载源码包的 go 工具会自动根据不同的域名调用不同的源码工具,对应关系如下:
BitBucket (Mercurial Git)GitHub (Git)Google Code Project Hosting (Git, Mercurial, Subversion)Launchpad (Bazaar)
所以为了 go get 命令能正常工作,你必须确保安装了合适的源码管理工具,并同时把这些命令加入你的 PATH 中。其实 go get 支持自定义域名的功能。
参数介绍:
-d 只下载不安装-f 只有在你包含了 -u 参数的时候才有效,不让 -u 去验证 import 中的每一个都已经获取了,这对于本地 fork 的包特别有用-fix 在获取源码之后先运行 fix,然后再去做其他的事情-t 同时也下载需要为运行测试所需要的包-u 强制使用网络去更新包和它的依赖包-v 显示执行的命令
Go语言的代码被托管于 网站,该网站是基于 Git 代码管理工具的,很多有名的项目都在该网站托管代码。其他类似的托管网站还有 、 等。
这些网站的项目包路径都有一个共同的标准,参见下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lZFb5vnB-1589278910682)(images/1.jpg)]
图中的远程包路径是 Go语言的源码,这个路径共由 3 个部分组成:
网站域名:表示代码托管的网站,类似于电子邮件 @ 后面的服务器地址。作者或机构:表明这个项目的归属,一般为网站的用户名,如果需要找到这个作者下的所有项目,可以直接在网站上通过搜索“域名/作者”进行查看。这部分类似于电子邮件 @ 前面的部分。项目名:每个网站下的作者或机构可能会同时拥有很多的项目,图中标示的部分表示项目名称。
默认情况下,go get 可以直接使用。例如,想获取 go 的源码并编译,使用下面的命令行即可:
go get /davyxu/cellnet
获取前,请确保 GOPATH 已经设置。Go 1.8 版本之后,GOPATH 默认在用户目录的 go 文件夹下。
cellnet 只是一个网络库,并没有可执行文件,因此在 go get 操作成功后 GOPATH 下的 bin 目录下不会有任何编译好的二进制文件。
需要测试获取并编译二进制的,可以尝试下面的这个命令。当获取完成后,就会自动在 GOPATH 的 bin 目录下生成编译好的二进制文件。
go get -u /gpmgo/gopm
查看你的GOPATH/bin目录下是否生成gopm.exe,src是否有gpmgo源码。
go package
包的基本概念
Go语言的包借助了目录树的组织形式,一般包的名称就是其源文件所在目录的名称,虽然Go语言没有强制要求包名必须和其所在的目录名同名,但还是建议包名和所在目录同名,这样结构更清晰。
包可以定义在很深的目录中,包名的定义是不包括目录路径的,但是包在引用时一般使用全路径引用。比如在GOPATH/src/a/b/ 下定义一个包 c。在包 c 的源码中只需声明为package c,而不是声明为package a/b/c,但是在导入 c 包时,需要带上路径,例如import “a/b/c”。
包的习惯用法:
包名一般是小写的,使用一个简短且有意义的名称。包名一般要和所在的目录同名,也可以不同,包名中不能包含- 等特殊符号。包一般使用域名作为目录名称,这样能保证包名的唯一性,比如 GitHub 项目的包一般会放到GOPATH/src//userName/projectName 目录下。包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。
一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。
包导入
单行导入
import "包 1 的路径"import "包 2 的路径"
多行导入
import ("包 1 的路径""包 2 的路径")
别名
package mainimport F "fmt"func main() {F.Println("C语言中文网")}
省略引用
package mainimport . "fmt"func main() {//不需要加前缀 fmt.Println("C语言中文网")}
标准的Go语言代码库中包含了大量的包,并且在安装 Go 的时候多数会自动安装到系统中。我们可以在 $GOROOT/src/pkg 目录中查看这些包。下面简单介绍一些我们开发中常用的包。
fmt
fmt 包实现了格式化的标准输入输出,这与C语言中的 printf 和 scanf 类似。其中的 fmt.Printf() 和 fmt.Println() 是开发者使用最为频繁的函数。
格式化短语派生于C语言,一些短语(%- 序列)是这样使用: %v:默认格式的值。当打印结构时,加号(%+v)会增加字段名;%#v:Go样式的值表达;%T:带有类型的 Go 样式的值表达。 io
这个包提供了原始的 I/O 操作界面。它主要的任务是对 os 包这样的原始的 I/O 进行封装,增加一些其他相关,使其具有抽象功能用在公共的接口上。bufio
bufio 包通过对 io 包的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。
在 bufio 各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据,只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。sort
sort 包提供了用于对切片和用户定义的集合进行排序的功能。strconv
strconv 包提供了将字符串转换成基本数据类型,或者从基本数据类型转换为字符串的功能。os
os 包提供了不依赖平台的操作系统函数接口,设计像 Unix 风格,但错误处理是 go 风格,当 os 包使用时,如果失败后返回错误类型而不是错误数量。sync
sync 包实现多线程中锁机制以及其他同步互斥机制。flag
flag 包提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。encoding/json
JSON 目前广泛用做网络程序中的通信格式。encoding/json 包提供了对 JSON 的基本支持,比如从一个对象序列化为 JSON 字符串,或者从 JSON 字符串反序列化出一个具体的对象等。html/template
主要实现了 web 开发中生成 html 的 template 的一些函数。net/http
net/http 包提供 HTTP 相关服务,主要包括 http 请求、响应和 URL 的解析,以及基本的 http 客户端和扩展的 http 服务。
通过 net/http 包,只需要数行代码,即可实现一个爬虫或者一个 Web 服务器,这在传统语言中是无法想象的。reflect
reflect 包实现了运行时反射,允许程序通过抽象类型操作对象。通常用于处理静态类型 interface{} 的值,并且通过 Typeof 解析出其动态类型信息,通常会返回一个有接口类型 Type 的对象。os/exec
os/exec 包提供了执行自定义 linux 命令的相关实现。strings
strings 包主要是处理字符串的一些函数集合,包括合并、查找、分割、比较、后缀检查、索引、大小写处理等等。
strings 包与 bytes 包的函数接口功能基本一致。bytes
bytes 包提供了对字节切片进行读写操作的一系列函数。字节切片处理的函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。log
log 包主要用于在程序中输出日志。
log 包中提供了三类日志输出接口,Print、Fatal 和 Panic。
Print 是普通输出;Fatal 是在执行完 Print 后,执行 os.Exit(1);Panic 是在执行完 Print 后调用 panic() 方法。
包管理工具
除了go工具链自带的工具比如,go build 、go vet 、go get 、 go doc 等等,还有包依赖管理工具。比如 dep等等,go 1.11 1.12 还添加了 go modules 。
一直依赖go语言被人吐槽的就是包依赖管理 和 错误处理方式。 社区出现了一批包依赖管理工具。
GOROOT 和GOPATH区别
两个概念:GOROOT 和GOPATH
GOROOT: 系统环境变量,就是我们存放下载的go语言源码的地方(go的源码,不是我们写的)。GOPATH: 环境变量,我们的工作空间,包括bin、pkg、src。是存放我们写的代码以及下载的第三方代码。
依赖,分为内部依赖和外部依赖。
内部依赖:
GOPATH和GOROOT,GOROOT并不是必须要设置的,但是GOPATH必须要设置,但并不是固定不变的。本项目内部依赖就会在GOPATH 所配置的路径下去寻找,编译器如果找不到会报错。总的来说内部依赖不需要太操心。
外部依赖包:
当我们要实现一些功能的时候,不可避免的需要一些第三方包,也统称为外部依赖包。go1.5之前只支持使用GOPATH来管理外部依赖包的,对比java的maven 和gradle等 简直不太方便。
Vendor 机制引入
在go1.5release之前,我们要管理多个依赖包版本时,只能通过设置多个GOPATH,拷贝代码来解决。比如,如果两个工程都依赖了Beego,一个1.5,一个1.8,那么必须设置俩GOPATH,并且还要记得切换。
go语言原生包缺陷:
能拉取源码的平台很有限,绝大多数依赖的是
不能区分版本,以至于令开发者以最后一项包名作为版本划分
依赖 列表/关系 无法持久化到本地,需要找出所有依赖包然后一个个 go get
只能依赖本地全局仓库(GOPATH/GOROOT),无法将库放置于局部仓库($PROJECT_HOME/vendor)
简单说,就是在你项目中多了一个vendor文件夹,go会把它默认作为GOPATH。让go编译时,优先从项目源码树根目录下的vendor目录查找代码(可以理解为切了一次GOPATH),如果vendor中有,则不再去GOPATH中去查找。
社区支持vendor的包管理库有很多,官方推荐的就有15种。
用的比较多的有dep(官方)、Godep、Govendor等等
go官方的包管理工具是dep,目前来看也是用的最多的,是官方建议使用的。
官方wiki各种对比: /golang/go/wiki/PackageManagementTools
安装方式也比较简单,下载对应平台可执行文件:/golang/dep/releases,拷贝到GOROOT/bin目录
在自己工作目录下,使用 dep 初始化会报错:
$ dep initinit failed: unable to detect the containing GOPATH: /home/zhongwei/work/my_project/go is not within a known GOPATH/src
也就是说项目开发定义在GOPATH目录才能使用
不希望将新项目的目录 my_project/go 加入到 GOPATH 中,觉得非常麻烦,另外看了consul源码发现都切换到了go module,此时只好放弃dep。
Go Modules
使用 go module 管理依赖后会在项目根目录下生成两个文件 go.mod 和 go.sum。
go.mod 中会记录当前项目的所依赖,文件格式如下所示:
module /gosoon/audit-webhookgo 1.12require (/elastic/go-elasticsearch v0./gorilla/mux v1./gosoon/glog v0.0.0-0521124921-a5fbfb162a81)
go.sum记录每个依赖库的版本和哈希值,文件格式如下所示:
/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA=/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg=/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=/gosoon/glog v0.0.0-0521124921-a5fbfb162a81 h1:JP0LU0ajeawW2xySrbhDqtSUfVWohZ505Q4LXo+hCmg=/gosoon/glog v0.0.0-0521124921-a5fbfb162a81/go.mod h1:1e0N9vBl2wPF6qYa+JCRNIZnhxSkXkOJfD2iFw3eOfg=
启用 go module 功能
(1) go 版本 >= v1.11
(2) 设置GO111MODULE环境变量
要使用go module 首先要设置GO111MODULE=on,GO111MODULE 有三个值,off、on、auto,off 和 on 即关闭和开启,auto 则会根据当前目录下是否有 go.mod 文件来判断是否使用 modules 功能。无论使用哪种模式,module 功能默认不在 GOPATH 目录下查找依赖文件,所以使用 modules 功能时请设置好代理。
在使用 go module 时,将 GO111MODULE 全局环境变量设置为 off,在需要使用的时候再开启,避免在已有项目中意外引入 go module。
使用 go module 功能
对于新建项目使用 go module:
go mod init /作者/项目名称
构建项目
go build hello.go
首先需要使用 go mod vendor 将项目所有的依赖下载到本地 vendor 目录中然后进行编译.
如代码中添加import
package mainimport . "fmt"import "/google/uuid"func main() {Println("helloword")uuid:=uuid.New()Println(uuid)}
执行命令(自動下載到vendor目录)
F:\code\go\helloworld>go mod vendorgo: finding module for package /google/uuidgo: downloading /google/uuid v1.1.1go: found /google/uuid in /google/uuid v1.1.1
go.mod中多了一行依赖
/google/uuid v1.1.1
go.sum中多了
/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
使用 Go 的其他包管理工具 godep、govendor、glide、dep 等都避免不了翻墙的问题,Go Modules 也是一样,但在go.mod中可以使用replace将特定的库替换成其他库:
replace (/x/text v0.3.0 => /golang/text v0.3.0)
也可以使用阿里云的镜像站:
go env -w GOPROXY=/goproxy/或者设置环境变量export GOPROXY=/goproxy/
go语法
变量定义
普通变量
package mainimport "fmt"type byte int8 //定义一个新的类型bytetype byteAlias = int8 //定义一个别名指向int8 实际类型还是int8func main() {var i, k int = 10, 100var ife bool = falsei = 100j := 100.5 //新变量根据值判断类型使用:= 必须要var关键字 后续赋值还是使用=j = 100.6fmt.Print(i + k)fmt.Print(ife)fmt.Println(j)ks := &i //引用指向 改了ks就等于改了i*ks = 10fmt.Println(*ks, i)const js int = 100 //常量fmt.Println(js)const (a = iota //引用一次累加一次 第一次是0b = iota //1c = iota //2)fmt.Println(a, b, c)var an byte = 1fmt.Printf("%T\n", an) //类型是main.bytevar an1 byteAlias = 1fmt.Printf("%T\n", an1) //类型是int8}
结构体和接口
package mainimport "fmt"/**结构体类似于类*/type User struct {userName stringuserEmail stringuserSex int}/**定义接口,定义方法参数是string类型返回值是int类型*/type Phone interface {call(string) int}/**定义实现结构*/type Iphone struct {}/**Iphone实现call方法*/func (iphone Iphone) call(message string) int {fmt.Println("iphone说了:" + message)return 1}func main() {user := User{"zs", "aa@", 0}fmt.Println(user.userEmail)user1 := User{userEmail: "app@"}fmt.Println(user1.userEmail)phone := new(Iphone)phone.call("helloworld")}
字符串
package mainimport ("fmt""strings")func main() {//字符串切割str := "a_b_c"var result []string = strings.Split(str, "_")fmt.Println(result)//字符串包含fmt.Println(strings.Contains(str, "c"))//字符串在另一个字符串位置 ,下标从0开始fmt.Println(strings.Index(str, "_"))//比较字符串 相等返回0 a<b返回-1 a>b返回1fmt.Println(pare(str, "a_b"))//返回某个字符串出现次数fmt.Println(strings.Count(str, "_"))//找到最后一个匹配字符的位置fmt.Println(strings.LastIndex(str, "_"))//是否某个字符开头fmt.Println(strings.HasPrefix(str, "a_"))//是否某个字符结尾fmt.Println(strings.HasSuffix(str, "a_"))//join数组元素拼接成sep分格字符串//[长度]定义指定长度数组,...根据值确定长度var strlist = []string{"a", "b"}var strlist1 = [...]string{"a", "b"}var strlist2 [2]stringstrlist2[0] = "zs"strlist2[1] = "ls"cc := strings.Join(strlist, ",")fmt.Println(cc, strlist1)//将某个字符串替换成目标字符串多少次fmt.Println(strings.Replace(str, "_", "-", strings.Count(str, "_")))//转换大小写fmt.Println(strings.ToUpper(str), strings.ToLower(str))//去除左右空格,去掉指定字符fmt.Println(strings.TrimSpace(" a b "), strings.TrimLeft("_abc_", "_"))//截取字符串 从开始索引到结束索引,包含开头不包含结尾。fmt.Println(str[1:2])}
数组
package mainimport "fmt"func main() {var k string = "a"//初始化带值var arr = [...]string{"zs", "ls"}arr1 := []string{"zs", "ls"}arr2 := [2]string{"zs", "ls"}fmt.Println(k, arr, arr1, arr2)//只定义不初始化var arr3 [3]stringarr3[0] = "zs"//修改数组值arr3[1] = "ls"fmt.Println(arr3)//获取数组值fmt.Println(arr3[1])//获取数组长度fmt.Println(len(arr3))//循环数组for i := 0; i < len(arr3); i++ {fmt.Println(i, arr3[i])}}
切片
package mainimport "fmt"func main() {//可以声明一个未指定大小的数组来定义切片:var idList []int//定义切片numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}//追加numbers和10到一个新的切片中,bumbers本身不变idList = append(numbers, 10)fmt.Println(numbers)fmt.Println(idList)/* 创建切片 numbers1 是之前切片的两倍容量*/numbers1 := make([]int, len(numbers), (cap(numbers))*2)/* 拷贝 numbers 的内容到 numbers1 */copy(numbers1, numbers)fmt.Println(numbers1)}
map
package mainimport "fmt"func main() {//var map_variable map[key_data_type]value_data_typekvs := map[string]string{"id": "1", "name": "zs"}fmt.Println(kvs)a := 1var b int = 10for k, v := range kvs {fmt.Println(k, v)}}
链表list
package mainimport ("container/list""fmt")func main() {//列表是一种非连续的存储容器,由多个节点组成,节点通过一些变量记录彼此之间的关系,列表有多种实现方法,如单链表、双链表等。userList:=list.New()userList.PushBack("zs")userList.PushFront("ls")fmt.Println(userList.Len())for i:=userList.Front();i!=nil;i=i.Next(){fmt.Println(i.Value)}}
流程控制
package mainimport ("bufio""fmt""os")func main() {in := bufio.NewReader(os.Stdin)str, _, err := in.ReadLine()if err != nil {fmt.Println(err.Error())}if string(str) == "1" {fmt.Print("boy")} else {fmt.Println("girl")}}
循环
package mainimport "fmt"func main() {//初始化带值var arr = [...]string{"zs", "ls"}//循环数组for i := 0; i < len(arr); i++ {fmt.Println(i, arr[i])}//range类似于foreach 参数1是索引参数2是指,不需要某个值可以使用_ ,一般用于map类型for index, value := range arr {fmt.Println(index, value)}for _, value := range arr {fmt.Println(value)}//条件循环,打印1-10所有奇数i := 0for i < 10 {i++if i%2 == 0 {continue}fmt.Printf("%v ", i)}fmt.Println()i = 0LOOP:for i < 10 {i++if i%2 == 0 {goto LOOP //等价于continue,也可以在任意地方定义label 根据逻辑goto}fmt.Printf("%v ", i)}}
函数
package mainimport "fmt"//func function_name( [parameter list] ) [返回值类型] {func add(i int, j int) int {return i + j}func calc(i int, j int) (int, int) {return i + j, i - j}func main() {fmt.Println(add(100, 34))addresult, minusResult := calc(100, 34)fmt.Println(addresult, minusResult)}
异常处理
package mainimport ("errors""fmt")/**error的接口定义type error interface {Error() string}*//**一般可以在函数最后一个参数添加一个错误参数,通过errors.New创建*/func div(num1 int,num2 int) (int,error){if(num2==0){return 0,errors.New("除数不能为0")}return num1/num2,nil}/**自定义异常,比如*/type Sex struct {sex int;//性别只能为0和1}func (sex Sex) Error() string{return fmt.Sprintf("性别字段%v只能为0和1", sex.sex)}func setSex(sex Sex)(string){if(sex.sex!=1 && sex.sex !=0){return sex.Error();}return ""}func main() {result,err:=div(100,0)if(err!=nil){fmt.Println(err)}else{fmt.Println(result)}sex:=Sex{2}errorMsg:=setSex(sex)fmt.Println(errorMsg)}
如果觉得《go语言入门教程01-go工具+go语法+go module》对你有帮助,请点赞、收藏,并留下你的观点哦!