Go系列一

一、语法基础

1、package:声明包。类似Java。Go程序是由包组成的。程序入口的包是main。

2、import:导入包。类似Java。利用圆括号可以导入多个包,或者逐个导入。

3、func:定义函数。

4、导出的名称,首字母是大写。

5、变量类型在变量名后面。

6、函数的命名参数,多个连续同类型,可以只保留最后一个类型。

x int, y int
// 简写成:
x, y int

7、函数返回值位于函数签名的尾部。

8、函数返回值可以有名字,并且像变量一样使用。

9、return语句没有参数,即返回各个变量的当前值。

10、:=,短声明变量,明确类型的赋值语句,只能用在函数内。

11、基本类型:bool,string,int,int8,int16,int32,int64,uint8,uint16,uint32,uint64,uintptr,byte,rune,float32,float64,complex64,complex128。 

12、var可以利用圆括号包含多个变量声明。 

13、没有初始化的变量,会被赋值为零值。类似C/C++中的默认值。数值类型为0,布尔类型为false,字符串类型为"",指针类型为nil,slice为nil,map为nil。

14、不同类型之间的转换,需要显式指定。C/C++支持隐式类型转换。 

15、类型推导:如果右值有明确类型,而左值没有,则左值的类型由右值推导得出。 

16、常量(const)不能使用:=。

17、只有for循环,并且没有圆括号,还可以在没表达式时省略分号。没有while循环。

// 死循环
for {
}

18、if条件语句没有圆括号。条件表达式前面可以有语句,并且语句中的变量可以在if和else中使用。

19、switch条件语句没有圆括号。条件表达式前面可以有语句。没有条件表达式,则等价于true。从上到下执行,直到匹配成功。 

20、defer:延迟函数调用。类似Objective-C的dispatch_async。defer函数会被压栈。 

21、指针不能运算。跟C/C++不同。

var p * int

22、结构体,利用点号访问字段。结构体指针也是用点号访问字段。

type DefaultCreator struct {
	clientSet *kubernetes.Clientset
}

23、结构体文法,通过字段值列表来创建一个结构体,键值对可以只列出部分字段。

type Vertex struct {
	X, Y int
}
var (
	v1 = Vertex{1, 2}  // 类型为 Vertex
	v2 = Vertex{X: 1}  // Y:0 被省略
	v3 = Vertex{}      // X:0 和 Y:0
	p  = &Vertex{1, 2} // 类型为 *Vertex
)

24、数组,长度是类型的一部分,不能改变。 

var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)

25、slice(切片),用make函数创建,用append函数添加元素。

// 序列
p := []int{2, 3, 5, 7, 11, 13}
len(p)
p[low:high] // 从下标low到high-1,省略low表示0,省略high表示len(p)
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
// 如果s太小,会分配更大的数组
func append(s []T, vs ...T) []T

26、for循环可以用range遍历slice和map。类似Python。

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {

}

27、range遍历可以使用下划线忽略key(slice的下标)和value。

for _, val := range pow {

}

28、map,用make函数创建。  

type Vertex struct {
	Lat, Long float64
}

var m map[string]Vertex // 不能添加元素

m = make(map[string]Vertex) // 用make才能添加元素
m["Bell Labs"] = Vertex{
	40.68433, -74.39967,
}

29、map文法。类似结构体文法,不过有键。

type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": Vertex{
		40.68433, -74.39967,
	},
	"Google": Vertex{
		37.42202, -122.08408,
	},
}
var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}
delete(m, "Google") // 删除键值对
v, ok := m["Answer"] // 检查是否包含键值对

30、函数也是值。类似C/C++函数指针。 

hypot := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	}
hypot(3, 4)

31、闭包

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
	pos(i)
	neg(-2*i)
} 

32、方法:没有类。包内任意数据类型都可以定义任意方法。但是其他包和基础数据类型不行。

type Vertex struct {
	X, Y float64
}
// Abs方法接收器是Vertex结构体的指针,即方法属于哪个数据类型
func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
v := &Vertex{3, 4}
// 方法接收器通过点号访问方法
v.Abs()

33、方法接收器是指针:1、可以避免方法调用时值拷贝;2、可以修改接收器。 

34、接口类型是一组方法的集合。接口类型的值可以是实现接口方法的任何类型。 

type Abser interface {
	Abs() float64
}

type Vertex struct {
	X, Y float64
}
func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

var a Abser
v := Vertex{3, 4}
a = &v

35、隐式接口。 

36、fmt包中的Stringer接口,error接口。io包中的Reader接口。image包。

type Stringer interface {
    String() string
}
// nil表示成功
type error interface {
    Error() string
}

37、http包,实现Handler接口来响应http请求。

package http

type Handler interface {
    ServeHTTP(w ResponseWriter, r *Request)
}

38、goroutine,轻量级线程。其实就是协程。共享进程的地址空间。

go f(x, y, z) // 创建一个新的goroutine来运行f函数。

39、channel,有类型的管道。类似C/C++中的pipe。 

func sum(a []int, c chan int) {
	sum := 0
	for _, v := range a {
		sum += v
	}
	c <- sum // 将和送入 c
}

a := []int{7, 2, 8, -9, 4, 0}

c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // 从 c 中获取
// 缓冲channel,100是缓冲的长度,缓冲满时,发送阻塞;缓冲空时,接收阻塞。
ch := make(chan int, 100)

40、for i := range ch循环会不断从channel接收值,直到channel被发送方关闭。  

v, ok := <-ch // 检查channel是否关闭

41、select,可以让一个goroutine在多个通信操作上阻塞等待,默认是default分支,语法很像switch。其实就是Linux内核中select的功能。

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

c := make(chan int)
quit := make(chan int)
go func() {
	for i := 0; i < 10; i++ {
		fmt.Println(<-c)
	}
	quit <- 0
}()
fibonacci(c, quit)

42、指针也是利用点号来访问。 

 

二、项目开发

1、使用go命令行工具,需要按照固定目录结构来组织代码。因为它是为了维护公共代码库(例如github)中的开源代码而设计的。 

2、GOPATH环境变量,指定工作目录。不能跟Go的安装目录相同。工作目录的bin子目录要添加到PATH环境变量中。

export PATH=$PATH:$GOPATH/bin

3、工作目录包含3个子目录:bin(可执行命令),pkg(包对象),src(源文件,按包组织,每个目录一个包)。

bin/
	streak                         # 可执行命令
	todo                           # 可执行命令
pkg/
	linux_amd64/
		code.google.com/p/goauth2/
			oauth.a                # 包对象
		github.com/nf/todo/
			task.a                 # 包对象
src/
	code.google.com/p/goauth2/
		.hg/                       # mercurial 代码库元数据
		oauth/
			oauth.go               # 包源码
			oauth_test.go          # 测试源码
	github.com/nf/
		streak/
		.git/                      # git 代码库元数据
			oauth.go               # 命令源码
			streak.go              # 命令源码
		todo/
		.git/                      # git 代码库元数据
			task/
				task.go            # 包源码
			todo.go                # 命令源码

4、包路径,可以是任意的唯一路径。

// 比较好的规范。基本路径
$GOPATH/src/github.com/yangwenhuan

5、构建并安装。构建好的二进制,默认安装在bin目录下。

// helloworld目录下有helloworld.go。
// 可以在任意路径执行这个命令,go命令行工具会根据GOPATH 到github.com/yangwenhuan/helloworld路径下查找源文件。
// 如果在helloworld目录下,直接执行go install即可。
go install github.com/yangwenhuan/helloworld

 

posted @ 2020-01-14 14:58  happyyoung  阅读(389)  评论(0编辑  收藏  举报