简介
Go是Google开发的一种静态强类型、编译型,并发型,并具有垃圾回收功能的编程语言
面向对象三大特性(封装/继承/多态), Go语言仅仅支持封装
1 2 3 4 5 6 7 package mainimport "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 ]Vertexm = 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 mainimport ( "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() }
接口
接口是一个或多个方法签名的集合, 任何类型的方法集中只要拥有对应的全部方法, 就表示实现了该接口, 无需显示添加接口声明 –摘自<Go学习笔记>
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 }
参考链接