Go 基础
环境配置
配置环境变量
在您所使用的
shell
对应的配置文件中,添加下面的内容:textexport GOROOT="/usr/local/go" export GOPATH="$HOME/go" export PATH=$PATH:$GOPATH/bin # Enable the go modules feature export GO111MODULE=auto # Set the GOPROXY environment variable export GOPROXY=https://goproxy.io
完成上面的操作后,在终端输入 go env
,输出下面内容,就表示 go 环境配置完成:
~ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/zhangpeng/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/zhangpeng/go"
GOPROXY="https://goproxy.io"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/sk/qbbrttxx2j1d7bqf02wh90zm0000gn/T/go-build233880756=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOROOT & GOPATH
GOROOT
Go
的安装目录内置的包和函数,如
fmt
、math
、strings
等都存储在这个目录的src
文件夹中GOPATH
Go
的工作目录src: 存放源代码。按照
Go
语言约定,go run
,go install
等命令默认会在此路径下执行;pkg: 存放编译时生成的中间文件( *.a );
bin: 存放编译后生成的可执行文件(在项目内执行 go install,会在 bin 目录下生成一个可执行文件)。
常用命令
go run
编译并执行,只能作用于命令源码文件,一般用于开发中快速测试。上文我们通过执行 go run test.go,完成了程序的编译运行。
go build
编译代码包或者源码文件。如果带上代码包名,则表示编译指定的代码包;如果带上源码文件,则表示编译指定源码文件。
go get
下载第三方代码包并编译安装,需要注意的是,它会下载安装到 GOPATH 环境变量配置的第一个工作区中。
go install
这个命令用于编译安装,可以作用于 main 包和非 main 包,然后将编译后的生成的执行文件存放到工程的 bin 目录下,将生成的归档文件(即静态链接库)存放到工程的 pkg 目录下。使用方式类似于 go build,可以在某个代码包目录下直接使用,也可以指定代码包使用。
go env
用于打印
GO
语言的环境信息,如GOPATH
是工作区目录,GOROOT
是GO
语言安装目录,GOBIN
是通过go install
命令生成可执行文件的存放目录(默认是当前工作区的bin
目录下),GOEXE
为生成可执行文件的后缀
数据类型
布尔型,整型,浮点型,指针类型(Pointer)、数组类型、结构化类型 (struct)、Channel 类型、函数类型、切片类型、接口类型(interface)、Map 类型
// 布尔型
bool
// -------------------------------------------------------
// 整型
int8 int16 int32 int64
uint8 uint16 uint32 uint64
// -------------------------------------------------------
// 浮点型
float32 float64
// -------------------------------------------------------
// 字符串
string
// -------------------------------------------------------
// 结构体,结构体是由一系列具有相同类型或不同类型的数据构成的数据集合
// 用结构体可以表示一个具有某一特征的对象
type identifier struct {
field1 type1
field2 type2
}
// -------------------------------------------------------
// 数组,有序的元素序列
// 可以通过访问数组下标即可对数组元素进行赋值
var variable_name [SIZE] variable_type
// -------------------------------------------------------
// 切片,类似"动态数组"结构的数据类型
// 本质是一个数据结构,实现了对数组操作的封装。
var identifier []type
// -------------------------------------------------------
// map
// 如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对
// 对于 map 类型,一定要进行初始化再赋值
var map_variable map[key_data_type]value_data_type
变量声明赋值
先声明,后赋值
go// 声明变量,变量名放在类型前 var name string // 赋值 name = "test"
声明并赋值
go// 编译器会根据值自行判定变量类型 // 方式 1 var name = "test" // 方式 2 name := "test"
常用类型初始化方式
// 结构体
type Person struct {
name string // 姓名
age uint32 // 年龄
birth string // 出生日期 用 yyyy/mm/dd 格式的字符串表示
height float32 // 身高
weight float32 // 体重
}
// 方式 1,变量 t 是一个指向 Person 的指针,此时结构体字段的值是它们所属类型的零值
t := new(Person)
// 方式 2,底层仍然会调用 new (),这里值的顺序必须按照字段顺序来写
person : &Person {name : "juejin", age : 12}
//----------------------------------
// 初始化数组
var array = [5]string{ "go", "java", "c++" }
array = [10] int64 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
//----------------------------------
// 初始化 int64 类型的切片
array = make([]int64, 10)
//----------------------------------
// map
dataMap := make(map[string]string)
条件语句
/*
* condition: 关系表达式或逻辑表达式,循环控制条件
*/
if condition {
}
eg.
if a == 10 {
/* 如果条件为 true 则执行以下语句 */
fmt.Println("a == 10" )
}
/*
* statement: 可选语句部分,在条件判断之前运行
* condition: 关系表达式或逻辑表达式,判断条件
*/
if statement; condition {
}
eg.
if a := 1 ; a < 10 {
// 如果条件为 true 则执行以下语句
fmt.Println("a < 10" )
}
循环语句
方式 1
/*
* init:一般为赋值表达式,给控制变量赋初值;
* condition:关系表达式或逻辑表达式,循环控制条件;
* post:一般为赋值表达式,给控制变量增量或减量。
*/
for init; condition; post {
}
eg.
for i :=1 ; i < 10 ; i ++ {
fmt.Println("i = " , i)
}
方式 2
/*
* condition:关系表达式或逻辑表达式,循环控制条件
*/
for condition { }
eg.
for 0 == 0 {}
for true {}
方式 3
for { }
eg.
for {
// 服务器监听 8080 端口
server.Listen(8080)
}
函数
go 语言中的函数是支持多返回值的
func function_name( [parameter list] ) [return_types] {
// 函数体
}
eg.
// 此函数实现了取两个数最大值的功能
func max(a int32, b int32) int32 {
if a > b {
return a
} else {
return b
}
}
// 此函数实现了取两个数最大值和最小值的功能
func getMaxAndMin(a int32, b int32) (int32, int32) {
if a > b {
return a, b
} else {
return b, a
}
}
go 语言还有一种特殊的函数,叫做方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。
func (variable_name variable_data_type) function_name() [return_type]{
/* 函数体*/
}
// 我们用 面向对象的思想实现一个封装的结构体
type Person struct{
name string // 姓名
age uint32 // 年龄
}
// 获取姓名
func (p *Person) GetName() string{
return p.name
}
// 获取年龄
func (p *Person) GetAge() uint32{
return p.age
}
// 设置姓名
func (p *Person) SetName(name string) {
p.name = name
}
// 设置年龄
func (p *Person) SetAge(age uint32) {
p.age = age
}
异常处理
结合自定义的 error 类型给出一个使用 panic 和 recover 的完整例子:
package main
import (
"fmt"
)
// 定义除法运算函数
func Devide(num1, num2 int) int {
if num2 == 0 {
panic("num cannot be 0")
} else {
return num1 / num2
}
}
func main() {
var a, b int
fmt.Scanf("%d %d", &a, &b)
defer func() {
if r := recover(); r != nil {
fmt.Printf("panic的内容%v\n", r)
}
}()
rs := Devide(a, b)
fmt.Println("结果是:", rs)
}
权限控制
在 go 语言中,是通过约定来实现权限控制的。变量和方法都遵守驼峰式命名。变量和方法的首字母大写,相当于 public
,变量和方法的首字母小写,相当于 private
。同一个包中访问,相当于 default
,由于 go
语言没有继承,所以也没有 protected
权限。
继承
go 语言是没有继承的。但是 go 语言可以通过结构体之间的组合来实现类似继承的效果。
package main
import "fmt"
type oo struct {
inner
ss1 string
ss2 int
ss3 bool
}
type inner struct {
ss4 string
}
func (i *inner) testMethod () {
fmt.Println("testMethod is called!!!")
}
func main() {
oo1 := new(oo)
fmt.Println("ss4 无值:"+oo1.ss4)
oo1.ss4 = "abc"
fmt.Println("ss4 已赋值"+oo1.ss4)
oo1.testMethod()//继承调用
oo1.inner.testMethod()//继承调用 这里也可以重写
}
多态
在 go 语言中,只要某个 struct 实现了某个 interface 的所有方法,那么我们就认为这个 struct 实现了这个类。
package main
import (
"fmt"
)
type Person interface {
Sing ()
}
type Girl struct {
Name string
}
type Boy struct {
Name string
}
func (this *Girl) Sing () {
fmt.Println("Hi, I am " + this.Name)
}
func (this *Boy) Sing () {
fmt.Println("Hi, I am " + this.Name)
}
func main() {
g := &Girl{"Lucy"}
b := &Boy{"Dave"}
p := map[int]Person{}
p[0] = g
p[1] = b
for _, v := range p {
v.Sing()
}
}