Go语言系列一

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安装说明

安装备用地址一

安装备用地址二

1569207934875

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运行

1569210187806

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!")
}

输出结果:

1569207497024

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

切片内部结构

切片声明

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

  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)
	}
}
posted @ 2019-08-31 22:38  电院院长  阅读(346)  评论(0编辑  收藏  举报