简介
Go是Google开发的一种静态强类型、编译型,并发型,并具有垃圾回收功能的编程语言
面向对象三大特性(封装/继承/多态), Go语言仅仅支持封装
1
2
3
4
5
6
7
package main
import "fmt"
func main () {
fmt.Println("Hello, World" )
}
类型
常用类型bool byte(uint8) string int(类型多, 就不一一列出了) float(float32, float64) complex(complex64, complex128)
var 语句定义了一个变量的列表
1
2
3
4
5
6
7
8
9
10
11
var andrew string
var liu string = "andrewliu"
k := 3
var f float32 = 3.2222
var z uint = uint (f)
const World = "世界"
控制流 if语句
if语言的condition不需要小括号
if语句的左大括号不能另起一行
可以在if语句中定义局部变量, 生命周期在if-else内
1
2
3
4
5
6
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n" , v, lim)
}
switch语句
switch语句不需要显式的使用break, 满足条件后会自动终止
1
2
3
4
5
6
7
8
9
10
11
func main () {
t := time.Now()
switch {
case t.Hour() < 12 :
fmt.Println("Good morning!" )
case t.Hour() < 17 :
fmt.Println("Good afternoon." )
default :
fmt.Println("Good evening." )
}
}
循环 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import "fmt"
func main () {
sum := 0
for i := 0 ; i < 10 ; i++ {
sum += i
}
fmt.Println(sum)
}
for sum < 1000 {
sum += sum
}
for {
fmt.Println("andrewliu" )
}
值得一提的是range, 类似迭代器操作, 返回(索引, 值)或 (键, 值)
1
2
3
4
5
6
7
var pow = []int {1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 }
func main () {
for i, v := range pow {
fmt.Printf("2**%d = %d\n" , i, v)
}
}
指针
Go竟然有指针, 我简直惊呆了
不支持指针运算, 不支持 -> 运算符, 直接.访问成员
1
2
3
4
5
i, j := 42 , 2701
p := &i
fmt.Println(*p)
*p = 21
fmt.Println(i)
数据结构 结构体
使用type定义新的结构体
值类型, 赋值和传参会复制全部内容
Go语言中没有类和继承的概念, 类似于类的机制可以通过struct来实现
struct支持嵌套
1
2
3
4
type Vertex struct {
X float64
Y float64
}
方法(可以理解为类的成员函数)
Go没有类, 但可以通过结构体定义方法, 方法接收者receiver是出现在func关键字和方法名之间的参数
方法不支持重载
receiver可以为结构体或者结构体指针
1
2
3
4
5
6
func (v *Vertex) Abs () float64 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
func main () {
fmt.Println(Vertex{1 , 2 })
}
数组
数组是值类型, 赋值和传参会复制整个数组
支持多维数组
1
2
3
4
var a [10 ]int
var b [...]int {1 , 2 , 3 , 4 }
slice是引用类型
slice并不是数组或数组指针, slice通过内部指针和相关属性(如长度, 容量)引用数组片段, 从来实现变长数组
读写操作实际目标是底层数组
当slice容量满后, append后会重新分配底层数组, 并复制数据(很想C++中vector), 通常以2被容量重新分配底层数组
1
2
3
4
5
6
7
s := []int {2 , 3 , 5 , 7 , 11 , 13 }
a := make ([]int , 5 )
func append (s []T, vs ...T) []T
map
引用类型, 底层数据结构为哈希表(O(1)查询时间复杂度)
键必须是支持相等运算符(==、!=)类型, 如 number、string、 pointer、array、struct,以及对应的 interface
不保证key的顺序性
从map中得到的value是value的复制(可以通过将value值设为指针来直接修改数据)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var m map [string ]Vertex
m = make (map [string ]Vertex)
var m = map [string ]Vertex{
"Bell Labs" : Vertex{
40.68433 , -74.39967 ,
},
"Google" : Vertex{
37.42202 , -122.08408 ,
},
}
if v, ok := m["Apple" ]; !ok {
}
for k, v := range m {
}
函数
支持不定长变参, 不支持默认参数
可以有多个返回值
函数可以作为参数传递
1
2
3
4
// 函数定义
func add(x int, y int) int {
return x + y // 可以有多个返回值
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
// 通过()一次导入多个包
import (
"fmt"
"time"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
fmt.Println("The time is", time.Now())
fmt.Println(" My name is Liubin")
}
函数作为参数
1
2
3
4
type FormatFunc func (s string , x, y int ) string // 定义函数类型。
func format (fn FormatFunc, s string , x, y int ) string {
return fn(s, x, y)
}
可变参数 , 只能有一个, 必须位于参数表最后.
1
2
3
4
5
6
7
8
func test (s string , n ...int ) string {
var x int
for _, i := range n {
x += i
}
return fmt.Sprintf(s, x)
}
匿名函数
1
2
3
fn := func () { println ("Hello, World!" ) }
fn()
defer 关键字defer 用于注册延迟调用, defer后跟的语句知道return前才被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
import (
"os"
"log"
)
func test () error {
file, err := os.Create("test.txt" )
if err != nil {
log.Fatal("create file err: " , err)
}
defer file.Close()
file.WriteString("Hello, World" )
return nil
}
func main () {
test()
}
接口
接口是一个或多个方法签名的集合, 任何类型的方法集中只要拥有对应的全部方法, 就表示实现了该接口, 无需显示添加接口声明 –摘自
1
2
3
4
type Stringer interface {
String() string
}
错误处理 error是一个build-in的接口
1
2
3
type error interface {
Error() string
}
如何使用错误处理呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func learnErrorHandling () {
m := map [int ]string {3 : "three" , 4 : "four" }
if x, ok := m[1 ]; !ok {
fmt.Println("no one there" )
} else {
fmt.Print(x)
}
if _, err := strconv.Atoi("non-int" ); err != nil {
fmt.Println(err)
}
}
并发 Go 提供并发特性, 类似于协程的goroutine机制(语言层面特性)
官方博客中对goroutinue的解释: A goroutine has a simple model: it is a function executing concurrently with other goroutines in the same address space. 在同一块地址空间多个goroutinue并发执行函数.
在函数调用语句前加一个go关键字, 就可以实现goroutine并发
多个goroutinue执行次序无法保证
channel用于多个goroutinue通信, 内部实现了同步来确保并发安全. 默认为同步模式, 需要发送和接收配对. 否则被阻塞
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func test_goroutinue () {
data := make (chan int )
exit := make (chan bool )
go func () {
for d := range data {
fmt.Println(d)
}
fmt.Println("recv over." )
exit <- true
}()
data <- 1
data <- 2
data <- 3
close (data)
fmt.Println("send over." )
<- exit
}
参考链接