IDE

这里我使用的IDE 是 GoLand,对应的License server为 http://idea.youbbs.org

常用命令

  • go get: 获取远程包
  • go run: 直接运行程序
  • go build: 测试编译,检查是否有编译错误
  • go fmt: 格式化编码(部分IDE在保存时自动调用)
  • go install: 编译包文件并编译整个程序
  • go test: 运行测试文件(通常以*_text.go命名)
  • go doc: 查看文档

创建本地的文档服务

在浏览器中输入 http://localhost:8080 即可访问本地的文档

godoc -http=:8080

枚举

这里定义的枚举就利用了go语言的特性,MB就等于1左移10位,以此类推

const (
    _ = iota
    KB float64 = 1 << (iota *10)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)

switch

go 中的switch 和其他语言不一样的地方是,我们并不需要在每一个分之后面都添加break,而且在switch 后面可以没有表达式
如果需要执行两个分支,可以使用fallthrough关键字

func grade(score int) string {

    g := ""
    switch {

        case score < 0 || score > 100:
            panic(fmt.Sprintf("Wrong score: %d", score))
        case score < 60:
            g = "F"
        case score < 80:
            g = "C"
        case score < 90:
            g = "B"
        case score <= 100:
            g = "A"
    }
    return g
}

函数

go 语言中的函数参数里,不可以设置参数默认值,但是返回值可以是多个,参数也可以使用函数类型,也可以使用可变参数列表


func apply(op func(int, int) int, a, b int) int { p := reflect.ValueOf(op).Pointer() // 获得当前函数的名字 opName := runtime.FuncForPc(p).Name() fmt.Printf("Calling function %s with args " + "(%d, %d)", opName, ab) return op(a,b) } func sum(numbers ...int) int { s := 0 for i := range numbers { s += numbers[i] } return s } func main() { fmt.Println(apply(func(a int, b int) int { return int(math.Pow(float64(a), float64(b))) }, 3, 4)) fmt.Println(sum(1, 2, 3, 4, 5)) }

指针

go 语言中的指针的定义和取地址的方式和 c 语言一致,但是不同之处在于,go 指针不可以运算

func swap(a, b *int) {
    *b, *a = *a, *b
}

func main() {
    a, b := 3, 4
    swap(&a, &b)
    fmt.Println(a, b)
}

数组声明、遍历

数组在go 中是值引用,在函数传递参数时,会整个拷贝一份,如果想直接更改数组中的值,可以传引用,但是通常不使用这种方法

func main() {
    var arr1 [5]int
    arr2 := [3]int{1, 2, 3}
    arr3 := [...]int{1, 2, 3, 4, 5}
    // grid 代表4行、5列
    var grid [4][5]bool
    fmt.Println(arr1, arr2, arr3, grid)

    // i = 数组下标, v = 数组值
    for i, v := range arr3 {
        fmt.Println(i, v)
    }
}

Slice(切片)

Slice 本身是没有数据的,是对底层array的一个view

arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
// s 的值为[2 3 4 5]
s := arr[2:6]

arr1 := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s := arr1[2:6]
// arr 的值变为[0, 1, 10, 3, 4, 5, 6, 7]
s[0] = 10

我们可以对Slice 进行 Reslice

s := arr[2:6]
s = s[:3]
s = s[1:]
s = arr[:]

slice 可以向后扩展,不可以向前扩展

arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
// s1 的值为[2 3 4 5]
s1 := arr[2:6]
// s2 的值为[5 6]
s2 := s1[3:5]

Slice 的底层实现包括ptr、len、cap三个值
prt 指向slice的头
len 代表slice的长度
cap 代表当前数组从ptr到结束的长度

在执行下面的代码时,我们可以发现,len的值就等于当前数组的长度,而cap的值,当len > cap 时, cap *= 2

func printSlice(s []int) {
    fmt.Println("len=%d, cap=%d\n", len(s), cap(s))
}

func main() {

    var s []int
    for i := 0; i < 100; i++ {
        printSlice(s)
        s = append(s, 2 * i +1)
    }
    fmt.Println(s)
}

在下面的例子中,s4、s5不在是数组arr 的view
在向数组添加元素时如果超过cap,系统会重新分配更大的底层数组

arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
// s2 的值为 [5 6]
s2 := s1[3:5]
// s3 的值为 [5 6 10]
s3 := append(s2, 10)
// s4 的值为 [5 6 10 11]
s4 := append(s3, 11)
// s5 的值为 [5 6 10 11 12]
s5 := append(s4, 12)

如果需要进行删除操作,可以对两个slice进行append

arr := []int{}
arr = append(arr, 0, 1, 2, 3, 4, 5, 6, 7)
arr = append(arr[:2], arr[3:]...)
// arr 的值为[0 1 2 4 5 6 7]
fmt.Println(arr)
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s2 := append(arr[:3], arr[4:]...)
// s2 的值为[0 1 2 4 5 6 7]
fmt.Println(s2)
// arr 的值为[0 1 2 4 5 6 7 7]
fmt.Println(arr)

Map

我们可以通过下面的方式创建一个Map,但是Map是无序的,不会按照我们初始化的顺序进行打印

m := map[string]string{
    "name":    "ccmouse",
    "course":  "golang",
    "site":    "imooc",
    "quality": "notbad",
}
// m2 == empty map
m2 := make(map[string]int) 
// m3 == nil
var m3 map[string]int 
fmt.Println("m, m2, m3:")
fmt.Println(m, m2, m3)

判断key是否存在value

courseName := m["course"]
fmt.Println(`m["course"] =`, courseName)

if causeName, ok := m["cause"]; ok {
    fmt.Println(causeName)
} else {
    fmt.Println("key 'cause' does not exist")
}

遍历一个map

for k, v := range m {
    fmt.Println(k, v)
}

删除key中的value

delete(m, "name")

使用时的注意事项

除了slice、map、function的内建类型都可以作为key
Struct类型不包含上述类型也可以作为key

字符和字符串

rune 相当于 go 的 char
使用range 遍历pos、rune对

s := "你好world"

for i, ch := range []rune(s) {
    // (0 你) (1 好) (2 w) (3 o) (4 r) (5 l) (6 d) 
    fmt.Printf("(%d %c) ", i, ch)
}

使用 utf8.RuneCountInString 获得字符数量
使用 len 获得字节长度
使用 []byte 获得字节

s := "你好world"

bytes := []byte(s)
for len(bytes) > 0 {

    ch, size := utf8.DecodeRune(bytes)
    bytes = bytes[size:]
    fmt.Printf("%c ", ch)
}

其他的字符操作 strings

  • Fields, Split, Join
  • Contains, Index
  • ToLower, ToUpper
  • Trim, TrimRight, TrimLeft

What doesn’t kill you makes you stronger.