Go的应用:
Docker
Codis
Glow类似于Hadoop
Cockroach
beego
.......
Go的中国社区
Go语言环境搭建
安装方式: Go源码安装,Go标准包安装,第三方工具安装,eg: GVM
编辑器
LiteIDE: Go语言开发工具 LiteIDE安装地址
Goland
Vscode + plugins (Code Runner)
Atom + Package: go-plus
/* !< Hello World */
package main
import "fmt"
func main(){
fmt.Print("Hello World!")
}
安装Go
链接:http://docscn.studygolang.com/doc/install
https://studygolang.com/dl
https://golang.google.cn/dl/
linux安装
- 下载二进制包:go1.13.linux-amd64.tar.gz
- 将下载的二进制包解压至 /usr/local目录
tar -C /usr/local -xzf go1.13.linux-amd64.tar.gz
- 将 /usr/local/go/bin 目录添加至PATH环境变量:
export PATH=$PATH:/usr/local/go/bin
//这个最好加在配置文件中eg: .profile 使用命令source $home/.profile执行
- notes:这些命令必须是作为根命令 or 通过sudo运行
Windows安装
Windows 下可以使用 .msi 后缀安装包来安装。
默认情况下 .msi 文件会安装在 c:\Go 目录下。将 c:\Go\bin (默认添加)目录添加到 Path 环境变量中。添加后需要重启命令窗口才能生效
安装测试
//创建工作目录 C:\>Go_WorkSpace
//test.go 测试代码
//基本程序结构
package main //包,表明代码所在的模块(包)
import "fmt" //引入代码依赖
//功能实现
func main() {
fmt.Print("hello World!")
}
输出结果:
Go的优点
Go提供了软件生命周期(开发、测试、部署、维护等等)的各个环节的工具,
eg: go tool, gofmt, go test
- 简洁 快速 安全
- 并行 有趣 开源 生产力
- 内存管理 数组安全 编译迅速
- C 37 C++ 84 Go 25
- 复合
软件开发的新挑战
- 多核硬件架构
- 超大规模分布式计算集群
- Web模式导致的前所未有的开发规模和更新速度
编写第一个Go程序
开发环境构建
GOPATH
-
在1.8版本前必须设置这个环境变量
-
1.8版本后(含1.8)如果没有设置使用默认值
在Unix上默认为$HOME/go, 在windows上默认为%USERPROFILE%/go
在Mac上GOPATH可以通过修改~/.bash_profile设置
go version
$GOPATH
目录约定有三个子目录src 存放源代码(比如:.go .c .h .s等) GOPATH下的src目录就是接下来开发程序的主要目录,所有的源码都是放在这个目录下面,那么一般我们的做法就是一个目录一个项目 pkg 编译时生成的中间文件(比如:.a) bin 编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中,如果有多个gopath,那么使用${GOPATH//://bin:}/bin添加所有的bin目录)
应用程序入口
- 必须是main包: package main
- 必须是main方法: func main()
- 文件名不一定是: main.go
退出返回值
- Go中main函数不支持任何返回值
- 通过os.Exit来返回状态
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Hello World!")
os.Exit(-1)
}
获取命令行参数
-
main函数不支持传入参数
func main(
arg [] string)- 在程序中直接通过os.Args获取命令行参数
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Args)
if len(os.Args) > 1 {
fmt.Println("Hello d!", os.Args[1])
}
}
/* !< output */
jason951018@ubuntu:~/go_learning/src/ch1/main$ go build hello_world.go
jason951018@ubuntu:~/go_learning/src/ch1/main$ ./hello_world xzp
[./hello_world xzp]
Hello d! xzp
The master has failed more times than the beginner has tried.
编写测试程序
-
源码文件以_test结尾: xxx_test.go
-
测试方法名以Test开头: func TestXXX(t *testing.T) {....}
Test后的第一字母必须大写
变量赋值
与其它主要编程语言的差异
- 赋值可以进行自动类型推断
- 在一个赋值语句中可以对多个变量进行同时赋值
常量定义
与其它主要编程语言的差异
快速设置连续值
const (
Monday = iota + 1
Tuesday
Wednesday
Thurday
Friday
Saturday
Sunday
)
const (
Open = 1 << iota
Close
Pending
)
基本数据类型
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte //alias for uint8
rune //alias for int32, represents a Unicode code point
float32 float64
complex64 complex128
类型转换
与其它主要编程语言的差异
- Go语言不允许隐式类型转换
- 别名和原有类型也不能进行隐式类型转换
类型的预定义值
- math.MaxInt64
- math.MaxFloat64
- math.MaxUint32
指针类型
与其它主要编程语言的差异
- 不支持指针运算
- string是值类型, 其默认的初始化值为空字符串,而不是nil
var s string
if s == "" {
}
算术运算符
A = 10 B = 20
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A+B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果2 |
% | 求余 | B % A 输出结果0 |
++ | 自增 | A++ 输出结果11 |
-- | 自减 | A--输出结果9 |
Go语言没有前置的++, --, (++a)
比较运算符
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回True,否则返回False | (A == B) 为False |
!= | 检查两个值是否不相等,如果不相等返回True,否则返回False | (A != B) 为True |
> | 检查左边值是否大于右边值,如果是返回True,否则返回False | (A > B) 为False |
< | 检查左边值是否小于右边值,如果是返回True,否则返回False | (A < B)为True |
>= | 检查左边值是否大于等于右边值,如果是返回True,否则返回False | (A >= B)为False |
<= | 检查左边值是否小于等于右边值,如果是返回True, 否则返回False | (A <= B)为True |
用==比较数组
- 相同维数且含有相同个数元素的数组才可以比较
- 每个元素都相同的才相等
逻辑运算符
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符,如果两边的操作数都是True,则条件True 否则为False | (A && B)为False |
|| | 逻辑 OR 运算符, 如果两边的操作数有一个True,则条件True 否则为False | (A || B)为True |
! | 逻辑 NOT 运算符, 如果条件为True,则逻辑NOT条件False,否则为True | !(A && B)为True |
位运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符"&"是双目运算符,其功能是参与运算的两数各对应的二进制相与 | (A & B) 结果为12, 二进制为 0000 1100 |
| | 按位或运算符"|"是双目运算符,其功能是参与运算的两数各对应的二进位相或 | (A | B)结果为61, 二进制为0011 1101 |
^ | 按位异或运算符"^"是双目运算符,其功能是参与运算的两数各对应的二进制相异或, | (A ^ B)结果为49, 二进制为0011 0001 |
<< | 左移运算符"<<"是双目运算符,左移n位就是乘以2的n次方,其功能把"<<"左边的运算数的各二进位全部左移若干位,由 "<<"右边的数指定移动的位数,高位丢弃,低位补 | A << 2结果为240 二进制为1111 0000 |
>> | 右移运算符">>"是双目运算符,右移n位就是除以2的n次方,其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数 | A >> 2结果为15 二进制0000 1111 |
位运算符
与其它主要编程语言的差异
&^按位置零
1 &^ 0 -- 1
1 &^ 1 -- 0
0 &^ 1 -- 0
0 &^ 0 -- 0
//右边置1 值为0
//右边置0 其值为左边的值
循环
与其它主要编程语言的差异
Go语言仅支持循环关键字 for
for j := 7; j <= 9; j++
//while 条件循环
//while (n < 5)
n := 0
for n < 5 {
n++
fmt.Println(n)
}
//无限循环
//while (true)
n := 0
for {
...
}
if 条件
if condition {
// code to be executed if condition is true
} else {
// code to be executed if condition is false
}
if condition-1 {
// code to be executed if condition-1 is true
} else if condition-2 {
// code to be executed if condition-2 is true
} else {
// code to be executed if both condition-1 and condition-2 are false
}
if 条件
与其它主要编程语言的差异
- condition 表达式结果必须为布尔值
- 支持变量赋值:
if var declaration; condition {
// code to be executed if condition is true
}
switch条件
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS x.")
//break
case "linux":
fmt.Println("Linux.")
default:
//freebsd, openbsd,
//plan9, windows...
fmt.Printf("%s.", os)
}
switch {
case 0 <= Num && Num <= 3:
fmt.Printf("0-3")
case 4 <= Num && Num <= 6:
fmt.Printf("4-6")
case 7 <= Num && Num <= 9:
fmt.Printf("7-9")
}
switch条件
与其它主要编程语言的差异
-
条件表达式不限制为常量或整数
-
单个case中,可以出现多个结果选项,使用逗号分隔
-
与C语言等规则相反,Go语言不需要用break来明确退出一个case
-
可以不设定switch之后的条件表达式,在此种情况下,整个switch结构
与多个if...else...的逻辑作用等同
数组的声明
var a [3]int //声明并初始化为默认零值
a[0] = 1
b := [3]int{1, 2, 3} //声明同时初始化
c := [2][2]int{{1, 2}, {3, 4}} //多维数组初始化
数组元素遍历
与其它主要编程语言的差异
func TestTravelArray(t *testing.T) {
a := [...]int{1, 2, 3, 4, 5} //不指定元素个数
for idx, elem := range a { //idx 索引, elem 元素
fmt.Println(idx, elem)
}
}
数组截取
a[开始索引(包含),结束索引(不包含)] //左闭右开,原因数组索引从零开始
a := [...]int{1, 2, 3, 4, 5}
a[1:2] //2
a[1:3] //2, 3
a[1:len(a)] //2, 3, 4, 5
a[1:] //2, 3, 4, 5
a[:3] //1, 2, 3
切片内部结构
切片声明
var s0 []int
s0 = append(s0, 1)
s := []int{}
s1 := []int{1, 2, 3}
s2 := make([]int, 2, 4)
/* []type, len, cap
其中len个元素会被初始化为默认零值,未初始化元素不可以访问
*/
切片共享存储结构
func TestSliceGrowing(t *testing.T) {
s := []int{}
for i := 0; i <= 10; i++ {
s = append(s, i) //地址发生变化,创建新的存储地址
t.Log(len(s), cap(s))
}
}
/* !< output */
=== RUN TestSliceGrowing
--- PASS: TestSliceGrowing (0.00s)
slice_test.go:26: 1 1
slice_test.go:26: 2 2
slice_test.go:26: 3 4
slice_test.go:26: 4 4
slice_test.go:26: 5 8
slice_test.go:26: 6 8
slice_test.go:26: 7 8
slice_test.go:26: 8 8
slice_test.go:26: 9 16
slice_test.go:26: 10 16
slice_test.go:26: 11 16
PASS
ok command-line-arguments 0.002s
func TestSliceShareMemory(t *testing.T) {
year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"}
Q2 := year[3:6]
t.Log(Q2, len(Q2), cap(Q2))
summer := year[5:8]
t.Log(summer, len(summer), cap(summer))
summer[0] = "Unkonw"
t.Log(Q2)
t.Log(year)
}
/* !< output */
=== RUN TestSliceShareMemory
--- PASS: TestSliceShareMemory (0.00s)
slice_test.go:34: [Apr May Jun] 3 9
slice_test.go:36: [Jun Jul Aug] 3 7
slice_test.go:38: [Apr May Unkonw]
slice_test.go:39: [Jan Feb Mar Apr May Unkonw Jul Aug Sep Oct Nov Dec]
PASS
ok command-line-arguments 0.002s
数组 vs 切片
- 容器是否可伸缩
- 是否可以进行比较
func TestSliceComparing(t *testing.T) {
a := []int{1, 2, 3, 4}
b := []int{1, 2, 3, 4}
if a == b {
t.Log("equal")
}
}
/* !< output */
slice_test.go:45:7: invalid operation: a == b (slice can only be compared to nil)
Map 声明
m := map[string]int{"one": 1, "two": 2, "three": 3} //string key类型 int value类型
m1 := map[string]int{}
m1["one"] = 1
m2 := make(map[string]int, 10, /*Initial Capacity */)
//why not init len?
//len 初始化为零值,map无法做到
Map元素的访问
与其它主要编程语言的差异
在访问的Key不存在时,仍会返回零值,不能通过返回nil来判断元素时否存在
if v , ok := m["four"]; ok {
t.Log("four", v)
} else {
t.Log("Not existing")
}
Map遍历
m := map[string]int{"one": 1, "two": 2, "three": 3}
for k, v := range m {
t.Log(k, v)
}
Map与工厂模式
- Map的value可以是一个方法
- 与Go的Dock type接口方式一起,可以方便的实现单一方法对象的工厂模式
func TestMapWithFunValue(t *testing.T) {
m := map[int]func(op int) int{}
m[1] = func(op int) int { return op }
m[2] = func(op int) int { return op * op }
m[3] = func(op int) int { return op * op * op }
t.Log(m[1](2), m[2](2), m[3](2))
}
实现Set
Go的内置集合中没有Set实现,可以map[type]bool
- 元素的唯一性
- 基本操作
- 1> 添加元素
- 2> 判断元素是否存在
- 3> 删除元素
- 4> 元素个数
func TestMapForSet(t *testing.T) {
mySet := map[int]bool{}
mySet[1] = true
n := 3
if mySet[n] {
t.Logf("%d is existing", n)
} else {
t.Logf("%d is not existing", n)
}
mySet[3] = true
t.Log(len(mySet))
delete(mySet, 1)
n = 1
if mySet[n] {
t.Logf("%d is existing", n)
} else {
t.Logf("%d is not existing", n)
}
}
请发表评论