目录
GO常用管理子命令
1. 介绍
2. 常用命令汇总
go version: 获取Go版本
go env: 查看Go环境变量
go help: 查看Go帮助命令
go get: 获取远程包(需提前安装git或hg)
go build: 编译并生成可执行程序
go run: 直接运行程序
go fmt: 格式化源码
go install: 编译包文件以及整个程序
go test: go原生提供的单元测试命令
go clean: 移除当前源码包和关联源码包里编译生成的文件
go tool: 升级Go版本时,修复旧版代码
godoc -http:80:开启一个本地80端口的web文档
gdb 可执行程序名:调试Go编译出来的文件
使用格式:
go command [arguments]
3. go build
示例:
// 编译当前目录为一个可执行文件
go build
// 编译当前目录为一个可执行文件
go build .
// 编译hello.go文件为一个可执行文件
go build hello.go
如果go build报错:
/usr/lib/go-1.10/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/tmp/go-link-008006128/000026.o: In function _cgo_05dc84caff82_Cfunc_sysconf':
/tmp/go-build/cgo-gcc-prolog:32: multiple definition
of_cgo_05dc84caff82_Cfunc_sysconf’
/tmp/go-link-008006128/000024.o:/tmp/go-build/cgo-gcc-prolog:32: first defined here collect2: error: ld returned 1 exit status
解决办法:
linux: export CGO_ENABLED=0
windows : cmd: set CGO_ENABLED=0
windows : powershell:$env:CGO_ENABLED=0
4. go run
命令格式:
go run 文件名.go
示例:
go run main.go
5. go install
可执行文件安装到: $GOPATH/bin/
可引用库安装到: $GOPATH/pkg/
注意: 没有开启go mod时,使用上述命令需要配置GOPATH,否则会报:no install location。
6. go get
命令格式:
下载包:添加 -u 参数可以自动更新包和依赖
go get github.com/**/**
使用安装的包
import "github.com/****/****"
如果下载慢,记得配置goproxy
# 设置module管理模式
$ go env -w GO111MODULE=on
# 设置下载源
$ go env -w GOPROXY=https://goproxy.cn
7. go fmt
go fmt命令可以格式化代码文件 使用go fmt命令,其实是调用了gofmt,而且需要参数-w,否则格式化结果不会写入文件
命令格式:
go fmt -w 文件名.go
示例:格式化整个项目
gofmt -w -l src
常见参数:
-l: 显示那些需要格式化的文件
-w: 把改写后的内容直接写入到文件中,而不是作为结果打印到标准输出。
-r: 添加形如"a[b:len(a)] -> a[b:]"的重写规则,方便我们做批量替换
-s: 简化文件中的代码
-d: 显示格式化前后的diff而不是写入文件,默认是false
-e: 打印语法错误到标准输出。无此参数只会打印不同行的前10个错误。
8. go tool
go tool fix .:用来修复以前老版本的代码到新版本
go tool vet directory|files:分析当前目录的代码是否正确
变量
1. 变量定义
Go 语言是静态类型的,变量声明时必须明确变量的类型。 Go 语言与其他语言显著不同的一个地方在于,Go 语言的类型在变量后面。比如 java 中,声明一个整体一般写成 int a = 1
,在 Go 语言中,需要这么写:
格式1:`var identifier type`
这种关键字的写法一般用于声明全局变量
var a int // 如果没有赋值,默认为0
var a int = 1 // 声明时赋值
var a = 1 // 声明时赋值
`var a = 1`,因为 1 是 int 类型的,所以赋值时,a 自动被确定为 int 类型,所以类型名可以省略不写
格式2:还有一种更简单的表达
// 这种方式相对来说用得更多一些
a := 1
msg := "Hello World!"
格式3:一次声明多个变量`var identifier1, identifier2 type`
var b, c int = 1, 2
**注意**:
* 变量需要定义后再使用
* := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
* 变量定义后没有使用编译会失败 **a declared but not used**
* go会根据值确定类型,也会根据类型自动确定值
GO的数据类型
Go的数据类型分为四大类:
基础类型----数字、字符串、布尔型
聚合类型----数组、结构体
引用类型----指针、slice、map、函数、管道
接口类型
1. 简单类型
简单例子:
package main
import (
"fmt"
// 反射模块,核心包括两方面:类型(reflect.Type)、值(reflect.Value)
"reflect"
)
func main() {
str1 := "Golang"
str2 := "Go语言"
var a int8 = 10
var c1 byte = 'a'
var b float32 = 12.2
var msg = "Hello World"
ok := false
fmt.Println(reflect.TypeOf(str2[2])) // uint8
fmt.Println(str1[2], string(str1[2])) // 108 l
fmt.Printf("%d %c\n", str2[2], str2[2]) // 232 è
fmt.Println("len(str2):", len(str2)) // len(str2): 8
}
2. Go 语言类型转换
类型转换用于将一种数据类型的变量转换为另外一种类型的变量。Go 语言类型转换基本格式如下:
type_name(expression)
* type_name 为类型
* expression 为表达式
以下实例中将整型转化为浮点型,并计算结果,将结果赋值给浮点型变量:
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值为: %f\n",mean)
}
以上实例执行输出结果为:
mean 的值为: 3.400000
3. 数组(array)与切片(slice)
Go 语言提供了数组类型的数据结构。
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:
一维数组的定义
var variable_name [SIZE] variable_type
定义了数组 balance 长度为 5 类型为 float32
var balance [5] float32
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
// 将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}
如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
数组取值
// 下标取值
variable_name[n]
// 切片取值
variable_name[slice]
综合小案例
arr := [5]int{1, 2, 3, 4, 5}
for i := 0; i < len(arr); i++ {
arr[i] += 100
}
fmt.Println(arr) // [101 102 103 104 105]
二维数组
var variable_name [SIZE][SIZE] variable_type
定义了数组 balance 长度为 10 *10类型为 float32
var balance [10][10]float32
4. 字典(键值对,map)
map 类似于 java 的 HashMap,Python的字典(dict),是一种存储键值对(Key-Value)的数据解构。使用方式和其他语言几乎没有区别。
// 仅声明
m1 := make(map[string]int)
// 声明时初始化
m2 := map[string]string{
"Sam": "Male",
"Alice": "Female",
}
// 赋值/修改
m1["Tom"] = 18
5.指针(pointer)
指针即某个值的地址,类型定义时使用符号*
,对一个已经存在的变量,使用 &
获取该变量的地址。
str := "Golang"
var p *string = &str // p 是指向 str 的指针
*p = "Hello"
fmt.Println(str) // Hello 修改了 p,str 的值也发生了改变
一般来说,指针通常在函数传递参数,或者给某个类型定义新的方法时使用。Go 语言中,参数是按值传递的,如果不使用指针,函数内部将会拷贝一份参数的副本,对参数的修改并不会影响到外部变量的值。如果参数使用指针,对参数的传递将会影响到外部变量。例如:
func add(num int) {
num += 1
}
func realAdd(num *int) {
*num += 1
}
func main() {
num := 100
add(num)
fmt.Println(num) // 100,num 没有变化
realAdd(&num)
fmt.Println(num) // 101,指针传递,num 被修改
}
-
reflect.TypeOf().Kind() 可以知道某个变量的类型,我们可以看到,字符串是以 byte 数组形式保存的,类型是 uint8,占1个 byte,打印时需要用 string 进行类型转换,否则打印的是编码值。
-
因为字符串是以 byte 数组的形式存储的,所以,
str2[2]
的值并不等于语
。str2 的长度len(str2)
也不是 4,而是 8( Go 占 2 byte,语言占 6 byte)。 正确的处理方式是将 string 转为 rune 数组
str2 := "Go语言"
runeArr := []rune(str2)
fmt.Println(reflect.TypeOf(runeArr[2]).Kind()) // int32
fmt.Println(runeArr[2], string(runeArr[2])) // 35821 语
fmt.Println("len(runeArr):", len(runeArr)) // len(runeArr): 4
转换成 `[]rune` 类型后,字符串中的每个字符,无论占多少个字节都用 int32 来表示,因而可以正确处理中文。
6. nil零值
nil是go语言中预先的标识符,我们可以直接使用nil,而不用声明它。
nil的常用写法:
file,err := funcName(xxx)
if err!= nil{
// do something....
fmt.Println("代码有错误")
}
* 获取函数返回值,其中当err不等于`nil`的时候,说明出现某些错误了,需要我们对这个错误进行一些处理
* 如果err等于`nil`说明运行正常。
那什么是nil
呢?
nil
的意思是无,或者是零值。
在Go语言中,如果你声明了一个变量但是没有对它进行赋值操作,那么这个变量就会有一个类型的默认零值。这是每种类型都有不同对应的零值:
nil的值类型必须是指针、通道、func、接口、映射或切片类型
类型 | 定义 | 零值 |
---|---|---|
bool | var variable bool | false |
int | var variable int | 0 |
string | var variable string | "" |
pointers | var a *int | nil |
slices | nil | |
maps | nil | |
channels | nil | |
functions | nil | |
interfaces | nil |
7. type
Go语言中type
关键字用于定义类型,因此又称为类型别名。
理解了type
关键字就会很容易理解Go语言中的函数、结构体、接口等。
使用`type`关键字定义类型
type NewType BaseType
类型定义是基于底层类型(BaseType)创建全新的类型(NewType),类型定义创建的是一个全新的类型,与其所基于的类型是两个不同的类型。
type math func(int, int) int //定义一个函数类型,两个 int 参数,一个 int 返回值
//定义一个函数 add,这个函数两个 int 参数一个 int 返回值,与 math 类型相符
func add(i int, j int) int {
return i + j
}
8. 数据的存储
所有像 int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值:
当使用等号 =
将一个变量的值赋值给另一个变量时,如:j = i
,实际上是在内存中将 i 的值进行了拷贝:
你可以通过 &i 来获取变量 i 的内存地址,例如:0xf840000040(每次的地址都可能不一样)。
值类型变量的值存储在堆中。
内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。
更复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。
一个引用类型的变量 r1 存储的是 r1 的值所在的内存地址(数字),或内存地址中第一个字所在的位置。
这个内存地址称之为指针,这个指针实际上也被存在另外的某一个值中。
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
当使用赋值语句 r2 = r1 时,只有引用(地址)被复制。
如果 r1 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2 也会受到影响。
9. 常量声明
常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义格式:
const identifier [type] = value
你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
- 显式类型定义: `const b string = "abc"`
- 隐式类型定义: `const b = "abc"`
多个相同类型的声明可以简写为:
const c_name1, c_name2 = value1, value2
以下实例演示了常量的应用:
package main
import "fmt"
func main() {
const LENGTH int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, false, "str" //多重赋值
area = LENGTH * WIDTH
fmt.Printf("面积为 : %d", area)
println()
println(a, b, c)
}
以上实例运行结果为:
面积为 : 50
1 false str
常量还可以用作枚举:
const (
Unknown = 0
Female = 1
Male = 2
)