Go 语言入门指南:基础语法和常用特性解析(中) | 青训营

65 阅读5分钟

Go语言入门指南(中)

基础语法

  1. 指针 Go语言也有类似于C语言的指针,在传入函数时只有指针操作才能更新对应变量。但是Go语言的指针相较于C语言,没有自增操作等运算,这综合了各种语言的指针特性。

    func add2ptr(n *int) {
        *n += 2
    }
    
    func main() {
        n := 5
        add2ptr(&n)
    }
    
  2. 结构体 Go语言也有类似C语言的结构体,可以通过 type name struct {} 的形式命名和定义结构体,如下代码主函数中给出了结构体初始化和内容访问示例。

    type user struct {
        name     string
        password string
    }
    
    func main() {
        // initialization
        a := user{name: "wang", password: "1024"}
        b := user{"wang", "1024"}
        c := user{name: "wang"}
        c.password = "1024"
        var d user
        d.name = "wang"
        d.password = "1024"
    }
    
  3. 结构体方法 在Go语言中,和C++的类成员函数相类似,也存在给结构体定义的函数,称为结构体方法。但是Go语言没有类等一系列概念,只存在结构体。 在定义结构体方法时,函数在结构体外部声明,需要在函数名前带上对应结构体参数,如 (u user) ,即为结构体方法。

    type user struct {
        name     string
        password string
    }
    
    func (u user) checkPassword(password string) bool {
        return u.password == password
    }
    
    func (u *user) resetPassword(password string) {
        u.password = password
    }
    
    func main() {
        a := user{name: "wang", password: "1024"}
        a.resetPassword("2048")
        fmt.Println(a.checkPassword("2048"))
    }
    
  4. 异常 Go语言对于异常处理也有较完整的工具链。 对于有异常情况的函数,在声明时一般会附加上一个返回参数作为异常返回参数。正常情况时为该参数传回 nil 值,异常时则调用 errors.New() 等函数创建异常类型变量并返回。

    type user struct {
        name     string
        password string
    }
    
    func findUser(users []user, name string) (v *user, err error) {
        for _, u := range users {
            if u.name == name {
                return &u, nil
            }
        }
        return nil, errors.New("not found")
    }
    
    func main() {
        u, err := findUser([]user{{"wang", "1024"}}, "wang")
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(u.name)
    }
    
  5. 字符串 Go语言的 strings 包含有丰富的字符串处理函数。和C++类似,字符串直接作为一个数据类型,并有丰富的处理工具。 下例涵盖了部分常用函数,注释为对应返回内容。

    func main() {
        a := "hello"
        strings.Contains(a, "ll") // true
        strings.Count(a, "l") // 2
        strings.HasPrefix(a, "he") // true
        strings.HasSuffix(a, "llo") // true
        strings.Index(a, "ll") // 2
        strings.Join([]string{"he", "llo"}, "-") // he-llo
        strings.Repeat(a, 2) // hellohello
        strings.Replace(a, "e", "E", -1) // hEllo
        strings.Split("a-b-c", "-") // [a b c]
        strings.ToLower(a) // hello
        strings.ToUpper(a) // HELLO
        len(a) // 5
    }
    
  6. 格式化输出 调用 fmt.Printf() 函数进行输出,可以实现类似于C语言的输出格式,使用百分号和一个字母组成的转换字符表示格式。如下代码有许多常用转换字符的示例,注释为对应输出内容。 而 fmt.Println() 函数则以跟 %v 差不多的方式格式化参数,并在最后添加一个换行符。

    type point struct {
        x, y int
    }
    
    func main() {
        s := "hello"
        n := 123
        p := point{1, 2}
        fmt.Println(s, n) // hello 123
        fmt.Println(p)    // {1 2}
    
        fmt.Printf("s=%v\n", s)  // s=hello
        fmt.Printf("n=%v\n", n)  // n=123
        fmt.Printf("p=%v\n", p)  // p={1 2}
        fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
        fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
    
        f := 3.141592653
        fmt.Println(f)          // 3.141592653
        fmt.Printf("%.2f\n", f) // 3.14
    }
    
  7. json json 是一种用于发送和接收结构化信息的标准协议,它主要由 encoding/json 包支持。 一个 json 结构体的变量名一般都为大写字母开头,可以在声明后附加 json:"name" 来将格式化输出的对应变量名改为小写字母。 下方代码展示了 json 信息的序列化与反序列化,在将对应结构体转换为 string 类型后,其输出也会带上更多信息。

    type userInfo struct {
        Name  string
        Age   int `json:"age"`
        Hobby []string
    }
    
    func main() {
        a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
        // Serialize
        buf, err := json.Marshal(a)
        if err != nil {
            panic(err)
        }
        fmt.Println(buf)         // [123 34 78 97...]
        fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
    
        buf, err = json.MarshalIndent(a, "", "\t")
        if err != nil {
            panic(err)
        }
        fmt.Println(string(buf))
        // { 
        //        "Name": "wang",
        //        "age": 18,
        //        "Hobby": [
        //                "Golang",
        //                "TypeScript"
        //        ]
        // }
    
        var b userInfo
        // Deserialize
        err = json.Unmarshal(buf, &b)
        if err != nil {
            panic(err)
        }
        fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
    }
    
  8. time Go语言的 time 包有丰富的与时间相关的方法。 包括获取当前时间,设置日期变量及其格式化,时间减法,时间解析,设置时间戳变量等。

    func main() {
        // Now
        now := time.Now()
    
        // Date
        t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
        t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
        t.Year() // 2022
        t.Month() // March
        t.Day() // 27
        t.Hour() // 1
        t.Minute() // 25
        t.Format("2006-01-02 15:04:05") // 2022-03-27 01:25:36
    
        // Sub
        diff := t2.Sub(t)
        diff.Minutes() // 65
        diff.Seconds() // 3900
        
        // Parse / Format
        t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
    
        // timestamp
        now.Unix()
    }
    
  9. 字符串与数字 在Go语言中,要实现字符串与数字的相互转换及其方便,在 strconv 包中有一系列成熟的函数可以调用。 其中, strconv.ParseInt("111", 10, 64) 的10代表十进制,64则代表精度。

    func main() {
        f, _ := strconv.ParseFloat("1.234", 64) // 1.234
    
        n, _ := strconv.ParseInt("111", 10, 64) // 111
    
        n, _ = strconv.ParseInt("0x1000", 0, 64) // 4096
    
        n2, _ := strconv.Atoi("123") // 123
    
        n2, err := strconv.Atoi("AAA")
        fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
    }
    
  10. 进程 Go语言的 os 包和 os/exec 包中包含一系列和操作系统交互的方法,并能够开启子进程。 以下代码展示了相关函数使用方法, os.Args 为该程序的传入参数切片。

    func main() {
        // args
        fmt.Println(os.Args)
    
        // environment
        fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
        fmt.Println(os.Setenv("AA", "BB"))
        
        // subprocess
        buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
        string(buf) // 127.0.0.1       localhost
    }