go语言基础| 青训营笔记

51 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

go语言基础

go语言的特性

1.高性能,高并发

2.语法简单,学习曲线平缓

3.丰富的标准库

4.完善的工具链

5.静态链表

6.快速编译

7.跨平台

8.垃圾回收

go语言基础语法

第一个hello world程序

package main
import (
   "fmt"
)
func main() {
   fmt.Println("hello world")
}

main包是程序的入口包,即为程序的入口文件。“fmt”是标准库中的一个包,主要功能有控制屏幕的输入输出,格式化字符串等。

变量的声明

package main
import (
   "fmt"
   "math"
)
func main() {
   var a = "initial"
   var b, c int = 1, 2
   var d = true
   var e float64
   f := float32(e)
   g := a + "foo"
   fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
   fmt.Println(g)                // initialapple
   const s string = "constant"
   const h = 500000000
   const i = 3e20 / h
   fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}

与其他编程语言不同,go先声明变量名,后面再跟变量类型。也可采用:=的方式自动分配变量类型。

数组与切片

package main
import "fmt"
func main() {
   var a [5]int
   a[4] = 100
   s := make([]string, 3)
   s[0] = "a"
   s[1] = "b"
   s[2] = "c"
   fmt.Println("get:", s[2])   // c
   fmt.Println("len:", len(s)) // 3
   s = append(s, "d")
   s = append(s, "e", "f")
   fmt.Println(s) // [a b c d e f]
   c := make([]string, len(s))
}

在真实的业务逻辑下go很少用数组去声明,因为一般长度都是固定的。go通常采用切片去定义一个可动态扩容的数组。感觉类似于java中的StringBuffer。

range快速遍历

package main
import "fmt"
func main() {
   nums := []int{2, 3, 4}
   sum := 0
   for i, num := range nums {
      sum += num
      if num == 2 {
         fmt.Println("index:", i, "num:", num) // index: 0 num: 2
      }
   }
}

对于数组range会返回两个值,第一个是下标,第二个是对应位置的value,如果不需要返回值,可用_来代替。range语法比较简洁,通常用于快速遍历数组或切片元素。

指针

package main
import "fmt"
func add2(n int) {
   n += 2
}
func add2ptr(n *int) {
   *n += 2
}
func main() {
   n := 5
   add2(n)
   fmt.Println(n) // 5
   add2ptr(&n)
   fmt.Println(n) // 7
}

go对指针的操作相对较少,与初学C语言时遇到的困难差不多,要弄清楚传入的到底是实参还是形参,操作与C中的指针类似。

结构体方法

package main
import "fmt"
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")) // true
}

类似于java中的类成员方法。

错误处理

package main
import (
   "errors"
   "fmt"
)
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) // wang
   if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
      fmt.Println(err) // not found
      return
   } else {
      fmt.Println(u.name)
   }
}

如果程序可能出现运行错误,在函数的返回值中可以加一个error。不同于java中的异常处理,go能够更清晰的知道哪个函数出现了错误。所以在接受返回值的时候要定义一个err用于接受错误的返回值。

json操作

package main
import (
   "encoding/json"
   "fmt"
)
type userInfo struct {
   Name  string
   Age   int `json:"age"`
   Hobby []string
}
func main() {
   a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
   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))
   var b userInfo
   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"}}
}

首先要保证结构体中的每个字段的首个字母要大写,以此来保证用json.Marshal()序列化的成功,序列化之后存于一个Byte数组,用string做强制类型转化方便查看。也可用json.Unmarshal()做反序列操作。

数字解析

package main
import (
   "fmt"
   "strconv"
)
func main() {
   f, _ := strconv.ParseFloat("1.234", 64)
   fmt.Println(f) // 1.234
   n, _ := strconv.ParseInt("111", 10, 64)
   fmt.Println(n) // 111
   n, _ = strconv.ParseInt("0x1000", 0, 64)
   fmt.Println(n) // 4096
   n2, _ := strconv.Atoi("123")
   fmt.Println(n2) // 123
   n2, err := strconv.Atoi("AAA")
   fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}

golang中strconv包实现数字和字符串的转换。 Atoi将字符串转换为数字,Rtoa实现反向操作。

进程信息

package main
import (
   "fmt"
   "os"
   "os/exec"
)
func main() {
   // go run example/20-env/main.go a b c d
   fmt.Println(os.Args)           // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
   fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
   fmt.Println(os.Setenv("AA", "BB"))
   buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
   if err != nil {
      panic(err)
   }
   fmt.Println(string(buf)) // 127.0.0.1       localhost
}

os.Getenv()和os.Setenv()用于获取和写入环境变量。

总结

go语言上手速度比较快,与其他语言相比都有不少共同点,所以学习起来较为轻松,同时其语法比较简洁明了,还省去了垃圾回收机制,能够使开发人员更专注于逻辑的开发编写。