美文网首页
Go 编程基础(一)

Go 编程基础(一)

作者: LL大L | 来源:发表于2018-06-21 10:11 被阅读11次

    欢迎来我的博客

    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到结束的长度

    15283633623331.jpg

    在执行下面的代码时,我们可以发现,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")
    

    使用时的注意事项

    <font color=red>除了slice、map、function的内建类型都可以作为key
    Struct类型不包含上述类型也可以作为key</font>

    字符和字符串

    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

    相关文章

      网友评论

          本文标题:Go 编程基础(一)

          本文链接:https://www.haomeiwen.com/subject/vfcqyftx.html