go语言入门教程01-go工具+go语法+go module

文章目录

  • 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是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。
相关网站:
go官网:https://golang.org/pkg/
go依赖包搜索:https://godoc.org/

go 安装

安装包下载地址为:https://golang.org/dl/。
window安装目录默认为:c:/go,bin目录自动指向bin目录。
linux解压tgz包,将bin目录添加到PATH变量中,假设go解压在/opt/go目录下

cat << 'EOF' >> ~/.bash_profile
PATH=$PATH:/opt/go/bin
export PATH
EOF

测试go是否正常安装

C:\Users\GVT>go version
go version go1.14.2 windows/amd64

go 常用命令

直接在终端中输入 go help 即可显示所有的 go 命令以及相应命令功能简介,主要有下面这些:

  • build: 编译包和依赖
  • clean: 移除对象文件
  • doc: 显示包或者符号的文档
  • env: 打印go的环境信息
  • bug: 启动错误报告
  • fix: 运行go tool fix
  • fmt: 运行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.go
package main
import "fmt"
func main(){
     
   fmt.Println("Hello World")
}
EOF

编译hello.go,然后运行可执行程序:

 go build hello.go

当前目录下生成了hello.exe,运行

GVT@DESKTOP-V14R68B MINGW64 ~/go
$ ./hello.exe
Hello World

而 go run 命令可以将上面两步并为一步执行(不会产生中间文件)。

$ go run hello.go
Hello 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 https://github.com/golang/tools golang.org/x/tools 
go安装目录/src新建golang.org\x\tools目录 拷贝源代码到该目录
cd C:\Go\src\golang.org\x\tools\godoc
go build golang.org/x/tools/cmd/godoc
go install golang.org/x/tools/cmd/godoc 自动拷贝到bin目录

install 命令

用来编译和安装go程序,我们可以将它与 build 命令对比:

生成的可执行文件路径 工作目录下的bin目录下 当前目录下
可执行文件的名字 与源码所在目录同名 默认与源程序同名,可以使用-o选项指定
依赖 将依赖的包放到工作目录下的pkg文件夹下 -

build build
生成的可执行文件路径 工作目录下的bin目录下 当前目录下
可执行文件的名字 与源码所在目录同名 默认与源程序同名,可以使用-o选项指定
依赖 将依赖的包放到工作目录下的pkg文件夹下 -

env 命令

查看所有环境变量

go env
go env | grep GOROOT

修改环境变量(设置中国区代理或者阿里云代理:https://mirrors.aliyun.com/goproxy/)

go env -w GOPROXY=https://goproxy.cn

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语言的代码被托管于 Github.com 网站,该网站是基于 Git 代码管理工具的,很多有名的项目都在该网站托管代码。其他类似的托管网站还有 code.google.com、bitbucket.org 等。
这些网站的项目包路径都有一个共同的标准,参见下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lZFb5vnB-1589278910682)(images/1.jpg)]

图中的远程包路径是 Go语言的源码,这个路径共由 3 个部分组成:

  • 网站域名:表示代码托管的网站,类似于电子邮件 @ 后面的服务器地址。
  • 作者或机构:表明这个项目的归属,一般为网站的用户名,如果需要找到这个作者下的所有项目,可以直接在网站上通过搜索“域名/作者”进行查看。这部分类似于电子邮件 @ 前面的部分。
  • 项目名:每个网站下的作者或机构可能会同时拥有很多的项目,图中标示的部分表示项目名称。

默认情况下,go get 可以直接使用。例如,想获取 go 的源码并编译,使用下面的命令行即可:

go get github.com/davyxu/cellnet

获取前,请确保 GOPATH 已经设置。Go 1.8 版本之后,GOPATH 默认在用户目录的 go 文件夹下。

cellnet 只是一个网络库,并没有可执行文件,因此在 go get 操作成功后 GOPATH 下的 bin 目录下不会有任何编译好的二进制文件。

需要测试获取并编译二进制的,可以尝试下面的这个命令。当获取完成后,就会自动在 GOPATH 的 bin 目录下生成编译好的二进制文件。

 go get -u github.com/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/github.com/userName/projectName 目录下。
  • 包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。
    一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。

包导入

单行导入

import "包 1 的路径"
import "包 2 的路径"

多行导入

import (
    "包 1 的路径"
    "包 2 的路径"
)

别名

package main
import F "fmt"
func main() {
     
    F.Println("C语言中文网")
}

省略引用

package main
import . "fmt"
func main() {
     
    //不需要加前缀 fmt.
    Println("C语言中文网")
}

标准的Go语言代码库中包含了大量的包,并且在安装 Go 的时候多数会自动安装到系统中。我们可以在 $GOROOT/src/pkg 目录中查看这些包。下面简单介绍一些我们开发中常用的包。

  1. fmt
    fmt 包实现了格式化的标准输入输出,这与C语言中的 printf 和 scanf 类似。其中的 fmt.Printf() 和 fmt.Println() 是开发者使用最为频繁的函数。
    格式化短语派生于C语言,一些短语(%- 序列)是这样使用:
  • %v:默认格式的值。当打印结构时,加号(%+v)会增加字段名;
  • %#v:Go样式的值表达;
  • %T:带有类型的 Go 样式的值表达。
  1. io
    这个包提供了原始的 I/O 操作界面。它主要的任务是对 os 包这样的原始的 I/O 进行封装,增加一些其他相关,使其具有抽象功能用在公共的接口上。
  2. bufio
    bufio 包通过对 io 包的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。
    在 bufio 各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据,只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。
  3. sort
    sort 包提供了用于对切片和用户定义的集合进行排序的功能。
  4. strconv
    strconv 包提供了将字符串转换成基本数据类型,或者从基本数据类型转换为字符串的功能。
  5. os
    os 包提供了不依赖平台的操作系统函数接口,设计像 Unix 风格,但错误处理是 go 风格,当 os 包使用时,如果失败后返回错误类型而不是错误数量。
  6. sync
    sync 包实现多线程中锁机制以及其他同步互斥机制。
  7. flag
    flag 包提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。
  8. encoding/json
    JSON 目前广泛用做网络程序中的通信格式。encoding/json 包提供了对 JSON 的基本支持,比如从一个对象序列化为 JSON 字符串,或者从 JSON 字符串反序列化出一个具体的对象等。
  9. html/template
    主要实现了 web 开发中生成 html 的 template 的一些函数。
  10. net/http
    net/http 包提供 HTTP 相关服务,主要包括 http 请求、响应和 URL 的解析,以及基本的 http 客户端和扩展的 http 服务。
    通过 net/http 包,只需要数行代码,即可实现一个爬虫或者一个 Web 服务器,这在传统语言中是无法想象的。
  11. reflect
    reflect 包实现了运行时反射,允许程序通过抽象类型操作对象。通常用于处理静态类型 interface{} 的值,并且通过 Typeof 解析出其动态类型信息,通常会返回一个有接口类型 Type 的对象。
  12. os/exec
    os/exec 包提供了执行自定义 linux 命令的相关实现。
  13. strings
    strings 包主要是处理字符串的一些函数集合,包括合并、查找、分割、比较、后缀检查、索引、大小写处理等等。
    strings 包与 bytes 包的函数接口功能基本一致。
  14. bytes
    bytes 包提供了对字节切片进行读写操作的一系列函数。字节切片处理的函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。
  15. 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语言原生包缺陷:

  • 能拉取源码的平台很有限,绝大多数依赖的是 github.com

  • 不能区分版本,以至于令开发者以最后一项包名作为版本划分

  • 依赖 列表/关系 无法持久化到本地,需要找出所有依赖包然后一个个 go get

  • 只能依赖本地全局仓库(GOPATH/GOROOT),无法将库放置于局部仓库($PROJECT_HOME/vendor)

简单说,就是在你项目中多了一个vendor文件夹,go会把它默认作为GOPATH。让go编译时,优先从项目源码树根目录下的vendor目录查找代码(可以理解为切了一次GOPATH),如果vendor中有,则不再去GOPATH中去查找。

社区支持vendor的包管理库有很多,官方推荐的就有15种。

用的比较多的有dep(官方)、Godep、Govendor等等

go官方的包管理工具是dep,目前来看也是用的最多的,是官方建议使用的。

官方wiki各种对比: https://github.com/golang/go/wiki/PackageManagementTools

安装方式也比较简单,下载对应平台可执行文件:https://github.com/golang/dep/releases,拷贝到GOROOT/bin目录

在自己工作目录下,使用 dep 初始化会报错:

$ dep init

init 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 github.com/gosoon/audit-webhook
go 1.12
require (
    github.com/elastic/go-elasticsearch v0.0.0
    github.com/gorilla/mux v1.7.2
    github.com/gosoon/glog v0.0.0-20180521124921-a5fbfb162a81
)

go.sum记录每个依赖库的版本和哈希值,文件格式如下所示:

github.com/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA=
github.com/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg=
github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gosoon/glog v0.0.0-20180521124921-a5fbfb162a81 h1:JP0LU0ajeawW2xySrbhDqtSUfVWohZ505Q4LXo+hCmg=
github.com/gosoon/glog v0.0.0-20180521124921-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 github.com/作者/项目名称

构建项目

 go build hello.go

首先需要使用 go mod vendor 将项目所有的依赖下载到本地 vendor 目录中然后进行编译.
如代码中添加import

package main

import . "fmt"
import "github.com/google/uuid"

func main() {
     
	Println("helloword")
	uuid:=uuid.New()
	Println(uuid)
}

执行命令(自動下載到vendor目录)

F:\code\go\helloworld>go mod vendor
go: finding module for package github.com/google/uuid
go: downloading github.com/google/uuid v1.1.1
go: found github.com/google/uuid in github.com/google/uuid v1.1.1

go.mod中多了一行依赖

github.com/google/uuid v1.1.1

go.sum中多了

github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

使用 Go 的其他包管理工具 godep、govendor、glide、dep 等都避免不了的问题,Go Modules 也是一样,但在go.mod中可以使用replace将特定的库替换成其他库:

replace (
    golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)

也可以使用阿里云的镜像站:

go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/
或者设置环境变量
export GOPROXY=https://mirrors.aliyun.com/goproxy/

go语法

变量定义

普通变量
package main

import "fmt"

type byte int8        //定义一个新的类型byte
type byteAlias = int8 //定义一个别名指向int8 实际类型还是int8
func main() {
     
	var i, k int = 10, 100
	var ife bool = false
	i = 100
	j := 100.5 //新变量根据值判断类型使用:= 必须要var关键字 后续赋值还是使用=
	j = 100.6
	fmt.Print(i + k)
	fmt.Print(ife)
	fmt.Println(j)

	ks := &i //引用指向 改了ks就等于改了i
	*ks = 10
	fmt.Println(*ks, i)

	const js int = 100 //常量
	fmt.Println(js)
	const (
		a = iota //引用一次累加一次 第一次是0
		b = iota //1
		c = iota //2
	)
	fmt.Println(a, b, c)

	var an byte = 1
	fmt.Printf("%T\n", an) //类型是main.byte
	var an1 byteAlias = 1
	fmt.Printf("%T\n", an1) //类型是int8
}
结构体和接口
package main

import "fmt"

/**
结构体类似于类
*/
type User struct {
     
	userName  string
	userEmail string
	userSex   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", "[email protected]", 0}
	fmt.Println(user.userEmail)
	user1 := User{
     userEmail: "[email protected]"}
	fmt.Println(user1.userEmail)
	phone := new(Iphone)
	phone.call("helloworld")

}

字符串
package main

import (
	"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 ab返回1
	fmt.Println(strings.Compare(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]string
	strlist2[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 main

import "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]string
	arr3[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 main

import "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 main

import "fmt"

func main() {
     
	//var map_variable map[key_data_type]value_data_type
	kvs := map[string]string{
     "id": "1", "name": "zs"}
	fmt.Println(kvs)
	a := 1
	var b int = 10

	for k, v := range kvs {
     
		fmt.Println(k, v)
	}

}
链表list
package main
import (
	"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 main

import (
	"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 main

import "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 := 0
	for i < 10 {
     
		i++
		if i%2 == 0 {
     
			continue
		}
		fmt.Printf("%v ", i)
	}
	fmt.Println()
	i = 0
LOOP:
	for i < 10 {
     
		i++
		if i%2 == 0 {
     
			goto LOOP //等价于continue,也可以在任意地方定义label 根据逻辑goto
		}
		fmt.Printf("%v ", i)
	}

}

函数

package main

import "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 main

import (
	"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)