闭包
package main
import "fmt"
func main() {
my_counter := counter()
fmt.Println(my_counter())
fmt.Println(my_counter())
fmt.Println(my_counter())
}
func counter() func() int {
i := 0
return func() int {
i++
return i
}
}
数组和切片
// 数组表示一个具有固定长度的序列
var arr = [5]int{1, 2, 3, 4, 5}
var arr1 = [...]int{1, 2, 3, 4, 5}
// 切片表示一个拥有相同类型的可变长序列
var slice = []int{1, 2, 3, 4, 5}
var slice1 = make([]int, 5, 10)
// slice2 的长度为 1, 指针指向 arr[3], 容量为 2
// 对 slice2 的改动会影响 arr
var slice2 = arr[3:4]
slice2[0] = 1
// 此时 arr[3] 为 1
// 切片具有三个属性: 指针 长度 容量
// 指针用于指向一个底层数组
// 长度表示切片允许打印的长度
len(slice)
// 容量表示底层数组的长度
cap(slice)
// 可以修改切片的长度, 但是不能超过容量
// 修改后的切片修改仍然对原数组有影响
slice2 = slice2[:2]
slice2[1] = 2
// 此时 arr[4] 为 2
// append 和 copy
// append 会修改底层数组
// 如果 append 后容量超过, 切片会复制整个底层数组并指向新数组
var new_arr = []int{0, 0, 0, 0, 0}
var new_slice = arr[0:2]
new_slice = append(new_slice, 1)
// 此时 new_arr[2] 为 1
// copy 会修改底层数组
new_slice1 := []int{1, 2, 3, 4, 5}
new_slice2 := []int{0, 0, 0}
new_slice3 := []int{0, 0, 0}
copy(new_slice2, new_slice1)
// 此时 new_slice2 为 {1, 2, 3}
copy(new_slice1, new_slice3)
// 此时 new_slice1 为 {0, 0, 0, 4, 5}
函数参数的区别
- 函数接受一个数组为值传递, 需要时间复制整个数组
- 函数接受一个切片为引用传递, 修改内容产生副作用
- 相同长度维度类型的数组可以相互比较
- 切片只能和 nil 比较
package main
import "fmt"
// 函数接受一个切片
func foo(a []int) {
a[0] = 1
}
// 函数接受一个数组
func foo5(a [5]int) {
a[1] = 2
}
func main() {
var n = []int{0, 0, 0, 0, 0}
foo(n)
fmt.Println(n[0])
// 1
var n5 [5]int
foo5(n5)
fmt.Println(n5[1])
// 0
foo(n5[:])
fmt.Println(n5[0])
// 1
}
并发
package main
import (
"fmt"
"time"
)
func say(s string, ch chan int) {
for {
time.Sleep(1 * time.Second)
// 此处从 ch 通道取出一个到 i 中
// 如果没有数据会进入等待
i := <-ch
fmt.Println(s)
fmt.Println(i)
}
}
func main() {
// chan 为一个通道, 缓存区大小为 10
// 默认没有缓冲区(0)
ch := make(chan int, 10)
// go 关键字表示函数作为一个协程运行
go say("world", ch)
i := 0
for {
// 此处将 i 放入 ch 缓冲区和通道
// 会连续打印 10 个 hello
// 之后由于 ch 的缓冲区和通道都有数据进入阻塞状态
ch <- i
fmt.Println("hello")
i++
}
// 关闭通道
close(ch)
}
select
package main
import (
"fmt"
"time"
)
func say1(ch chan int) {
for {
ch <- 1
time.Sleep(1 * time.Second)
}
}
func say2(ch chan int) {
for {
ch <- 2
time.Sleep(2 * time.Second)
}
}
func main() {
ch1 := make(chan int, 10)
ch2 := make(chan int, 10)
go say1(ch1)
go say2(ch2)
for {
select {
// 如果多个 case 同时满足会随机挑选一个进行处理
// 其他的继续等待
case _ = <-ch1:
fmt.Println()
fmt.Println("Say1 Get")
case _ = <-ch2:
fmt.Println("Say2 Get")
// 如果没有符合的信号, 且没有 default
// select 会进入等待
// 如果有 default 就直接运行 default 的内容
default:
fmt.Println("Nothing")
}
time.Sleep(500 * time.Millisecond)
}
}
其他用法
Golang 调用 C
package main
// int add(int a, int b) {
// return a + b;
// }
import "C"
// 将 C 代码注释, 下面写 import
// import "C" 和上面的 C 代码之间必须没有空行
import "fmt"
func main() {
a := C.int(1)
b := C.int(2)
value := C.add(a, b)
fmt.Printf("%v\n", value)
}