初始入门可以参考菜鸟教程 ,整体比较系统,也是入门参考的文档,涉及的相关字面内容,在此不进行赘述。仅记录一些,相比python、perl而言的个性化特点。
基础语法记录
用的比较多,教程中也没有展开介绍,列在这,后续有需要的情况下,酌情补充。
| key_word | 示例 | 说明 |
|---|---|---|
| break | ||
| default | ||
| func | ||
| interface | ||
| select | ||
| case | ||
| defer | ||
| go | ||
| map | ||
| struct | ||
| chan | ||
| else | ||
| goto | ||
| package | ||
| switch | ||
| const | ||
| fallthrough | ||
| if | ||
| range | ||
| type | ||
| continue | ||
| for | ||
| import | ||
| return | ||
| var |
变量声明
- 变量声明需要明确声明,这在perl、python中可能没有那么严格, 声明支持
var x types或x := ""两种方式 - 常量有单独的声明,
const identifier [type] = value,用来声明不会进行改变的值(只支持布尔型、数字型和字符串型)。在使用常量时候,会生成一个自增长的特殊变量iota,会对未赋值的常量进行自动复制。这部分在使用中需要注意。
运算符
常规运算符,这里不进行展开了,其中赋值运算符遇到两个之前没有遇到过的, <<= 和 >>= ,左移后复制,和右移后赋值。之前在其他语言没见过的。其实就是将对应的整数型数值转换成 2进制的值,然后对二进制的数据进行移动后得到一个新的二进制数据,然后解析成整数。
| 运算符 | 描述 | 实例 |
|---|---|---|
| <<= | 左移后赋值 | C <<= 2 等于 C = C << 2 |
| >>= | 右移后赋值 | C >>= 2 等于 C = C >> 2 |
条件语句
在 GO中,不支持三目运算符。所以不能使用类似python中的 maxNum = a if a > b else b
函数
哎,为啥所有编程语言的函数声明格式不能一致点呢,哪怕关键字统一统一也行呀。有 sub、def 在go里面的关键字是func
Go语言的函数定义示例如下:
1 | func function_name( [parameter list] ) [return_types] { |
相比于其他的语言,比较特殊的是需要声明返回值的数据类型。如果函数有返回值,则该参数是必须的!如果返回多个值,则需要声明每个值的数据类型。
1 | /* 函数返回两个数的最大值 */ |
在go语言中,同时支持值传递(传递数值,变更不会影响函数外的变量)和引用传递(传递地址,变更会影响函数外的变量)。
作用域
这部分和其他编程语言基本一致。
数组
这部分比较特殊的,就是在声明数组类型的时候,可以指定元素个数
1 | //格式 |
指针
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。
1 | var var_name *var-type |
结构体
可以简单的理解成其他语言中的对象/类。结构体在定义完成后,就属于一种可以用于声明的变量。对应的结构体也可以作为函数的传入参数。
1 | type Books struct { |
切片
切片和python的数组概念类似,go语言的数组更像是python中的元组。
切片的一些方法
| 方法 | 示例 | 说明 |
|---|---|---|
| len() | len(x) | 获取切片的长度。 |
| cap() | cap(x) | 可以测量切片最长可以达到多少 |
| append() | x = append(x, 1) | 切片中追加一个元素 |
| copy() | copy(x,x1) | 拷贝一个切片 |
集合
和python的字典,perl的hash类似。
不过不通过的是,Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。
1 | /* 使用 make 函数定义一个集合 */ |
遍历
语言范围,看下来其实相当于其他编程语言中的遍历,包括遍历数组,字典等结构。遍历返回值均为2个,第一项为索引,第二项为值。
1 | map1 := make(map[int]float32) |
递归
Go 语言支持递归。但我们在使用递归时,需要设置退出条件,否则递归将陷入无限循环中。
尤其注意的是,go是支持函数的递归的(函数中调用函数自身),这在其他的语言中其实很少见,会存在先有鸡还是先有蛋的逻辑悖论。
递归的一个示例如下:
1 | //通过 Go 语言的递归函数实例阶乘 |
前面的阶乘等方法可能本身不能凸显递归本身的优势,但是从求指定精度的平方根来看,递归确实有其独特的数学应用基础。
语言接口
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
看下来,和 python中对象的方法比较类似,不是一个独立的函数,而是依托于对应的数据类型的方法。
go并发
这可能是go之所以能脱颖而出的重要优势。Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
在使用go进行多线程分析的时候,可以使用直接在对应的函数前添加go即可。(go中的多线程是无序的,所以go中的程序执行顺序必须是不影响业务逻辑的)
1 | package main |
Goroutine的规则:
当新的Goroutine开始时,Goroutine调用立即返回。与函数不同,go不等待Goroutine执行结束。当Goroutine调用,并且Goroutine的任何返回值被忽略之后,go立即执行到下一行代码。
main的Goroutine应该为其他的Goroutines执行。如果main的Goroutine终止了,程序将被终止,而其他Goroutine将不会运行。
go 通道
通道(channel)是用来传递数据的一个数据结构。通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
go语言中,除了直接共享内存,还可以在多个goriutine之间完成数据通信,实现数据共享。
1 | // 创建通道 chan关键字,后面是缓冲区的数据类型 |
注意: 默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
注意: 如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。
1 | func sum(s []int, c chan int) { |
遍历和关闭通道
Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片。格式如下:v, ok := <-ch , 不过为了区分通道是在等待还是已经终止存储,需要在通道存储数据结束后,对通道进行关闭 close(ch) 。
通道除了作为数据的通信,还可以用来确保对应的子线程执行完成(利用通道的阻塞功能)。