Go的应用:

Docker

Codis

Glow类似于Hadoop

Cockroach

beego

.......

Go的中国社区

Golang中国

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/

Go安装说明

安装备用地址一

安装备用地址二

linux安装

  1. 下载二进制包:go1.13.linux-amd64.tar.gz
  2. 将下载的二进制包解压至 /usr/local目录
tar -C /usr/local -xzf go1.13.linux-amd64.tar.gz
  1. 将 /usr/local/go/bin 目录添加至PATH环境变量:
export PATH=$PATH:/usr/local/go/bin
//这个最好加在配置文件中eg: .profile 使用命令source $home/.profile执行
  1. 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
  • 复合

软件开发的新挑战

  1. 多核硬件架构
  2. 超大规模分布式计算集群
  3. Web模式导致的前所未有的开发规模和更新速度

编写第一个Go程序

开发环境构建

GOPATH

  1. 在1.8版本前必须设置这个环境变量
  2. 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目录)

应用程序入口

  1. 必须是main包: package main
  2. 必须是main方法: func main()
  3. 文件名不一定是: main.go

退出返回值

  1. Go中main函数不支持任何返回值
  2. 通过os.Exit来返回状态
package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Hello World!")
    os.Exit(-1)
}

获取命令行参数

  1. main函数不支持传入参数
    func main(arg [] string)
  1. 在程序中直接通过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.

编写测试程序

  1. 源码文件以_test结尾: xxx_test.go
  2. 测试方法名以Test开头: func TestXXX(t *testing.T) {....}
    Test后的第一字母必须大写

变量赋值

与其它主要编程语言的差异

  1. 赋值可以进行自动类型推断
  2. 在一个赋值语句中可以对多个变量进行同时赋值

常量定义

与其它主要编程语言的差异

快速设置连续值

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

类型转换

与其它主要编程语言的差异

  1. Go语言不允许隐式类型转换
  2. 别名和原有类型也不能进行隐式类型转换

类型的预定义值

  1. math.MaxInt64
  2. math.MaxFloat64
  3. math.MaxUint32

指针类型

与其它主要编程语言的差异

  1. 不支持指针运算
  2. 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

用==比较数组

  1. 相同维数且含有相同个数元素的数组才可以比较
  2. 每个元素都相同的才相等

逻辑运算符

运算符

描述

实例

&&

逻辑 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 条件

与其它主要编程语言的差异

  1. condition 表达式结果必须为布尔值
  2. 支持变量赋值:
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条件

与其它主要编程语言的差异

  1. 条件表达式不限制为常量或整数
  2. 单个case中,可以出现多个结果选项,使用逗号分隔
  3. 与C语言等规则相反,Go语言不需要用break来明确退出一个case
  4. 可以不设定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

切片内部结构

go语言编程规范 go语言chan_golang

切片声明

var s0 []int
s0 = append(s0, 1)

s := []int{}

s1 := []int{1, 2, 3}

s2 := make([]int, 2, 4)
/* []type, len, cap
    其中len个元素会被初始化为默认零值,未初始化元素不可以访问
*/

切片共享存储结构

go语言编程规范 go语言chan_Go_02

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 切片

  1. 容器是否可伸缩
  2. 是否可以进行比较
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. 基本操作
  • 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)
    }
}