Golang 一些基本语法

2020-07-02
2分钟阅读时长

闭包

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)
}