GoLang基础语法|青训营笔记

131 阅读6分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

GoLang

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

基础语法

变量声明

  • var name string = ""

    • 会自动推导变量类型
  • 变量 := 值

常量

  • var 改成 const,Go中常量没有确定的类型,会根据上下文自动确定类型

判断

  • 与C++相似

  • 不同点

    • if后语句没有括号
    • if后必须接大括号

循环

  • Go中只有for循环
  • 且for循环的条件语句不需要加括号
  • break和continue与C++功能相同

switch

  • switch后的变量名不需要加括号

  • Go中的switch不需要在每个case中加break语句(C++中没有break语句会继续往下跑完所有的case)

  • Go中的switch可以使用任意的变量类型,可以取代if else

    • switch {
          case t.Hour() < 12:
              fmt.Println("It's before noon")
          default:
              fmt.Println("It's after noon")
      }
      

数组

  • 特性与C++相似
  • 长度固定,真实业务代码很少直接使用
  • var a [5]int //声明一个可以存放5个int元素的数组A
    b := [5]int{1,2,3,4,5} //枚举声明
    

切片

  • 可以任意更改长度
  • //make创建切片
    s := make([]string, 3)
    //可以像数组一样赋值
    s[2] = 'c'
    //append追加元素(用法是必须把append的结果赋值为原数组)
    s = append(s, "d")
    //len取切片长度
    length = len(s)
    //复制切片,从后到前
    copy(c, s)
    //同python的切片操作,但不支持负数索引
    s[2:3] //[c,d]
    

map

  • 类似C++中的哈希表
  • //make创建,第一个是key的类型,这里是string;第二个是value的类型,这里是int
    m := make(map[string]int)
    //delete删除键值对
    delete(map_name, map_key)
    
  • GoLang的map是完全无序的,遍历时也不会按照字母排序,也不会按照插入顺序输出,而是随机顺序

range

  • range用来快速遍历slice和map
  • 遍历时会返回两个值,第一个是索引,第二个是对应位置的值
  • 不需要索引就用下划线来忽略
  • 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
        }
    }
    fmt.Println(sum) //9
    

函数

  • 变量类型后置

  • 支持返回多个值,实际的业务逻辑代码中几乎所有函数都返回两个值

    • 第一个是真正的返回结果,第二个值是一个错误信息。
    package main
    import "fmt"
    func add(a int, b int) int {
        return a + b
    }
    ​
    func add2(a, b int) int {
        return a + b
    }
    ​
    func exists(m map[string]string, k string) (v string, ok bool) {
        v, ok = m[k]
        return v, ok
    }
    ​
    func main() {
        res := add(1, 2)
        fmt.Println(res) // 3
        v, ok := exists(map[string]string{"a": "A"}, "a")
        fmt.Println(v, ok) // A True
    }
    

指针

  • 主要用途为对传入参数进行修改
  • 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 传入函数的参数实际上是一个拷贝,该函数只是对拷贝值+2,没有改变实际变量
        add2ptr(&n)
        fmt.Println(n) // 7 指针指向地址就能真正的改变变量的值
    }
    

结构体

  • 结构体是带类型的字段的集合
  • 结构体也支持指针
  • package main
    import "fmt"
    type user struct {
    	name     string
    	password string
    }
    
    func main() {
    	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"
    	fmt.Println(a, b, c, d)   // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
    	fmt.Println(checkPassword(a, "haha"))   // false
    	fmt.Println(checkPassword2(&a, "haha")) // false
    }
    
    func checkPassword(u user, password string) bool {
    	return u.password == password
    }
    
    func checkPassword2(u *user, password string) bool {
    	return u.password == password
    }
    

结构体方法

  • 实现结构体的两种写法

    • 带指针

      • 可以对结构体进行修改
    • 不带指针

      • 实际上进行的是拷贝操作,无法进行修改
  • 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
    }
    

错误处理

  • 使用一个单独的返回值来传递错误信息

  • go语言能够很清晰的指导那个函数返回了错误,并且能用简单的if else来处理错误

  • 函数实现需要return两个值

    • 出现错误可以是return nil和 error
    • 没错误就返回原本的结果和nil
  • 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)
    	}
    }
    

字符串操作

  • 库函数strings包中有很多常用的字符串工具函数
  • package main
    import (
    	"fmt"
    	"strings"
    )
    func main() {
    	a := "hello"
    	fmt.Println(strings.Contains(a, "ll"))                // true
    	fmt.Println(strings.Count(a, "l"))                    // 2
    	fmt.Println(strings.HasPrefix(a, "he"))               // true
    	fmt.Println(strings.HasSuffix(a, "llo"))              // true
    	fmt.Println(strings.Index(a, "ll"))                   // 2
    	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
    	fmt.Println(strings.Repeat(a, 2))                     // hellohello
    	fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
    	fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]
    	fmt.Println(strings.ToLower(a))                       // hello
    	fmt.Println(strings.ToUpper(a))                       // HELLO
    	fmt.Println(len(a))                                   // 5
    	b := "你好"
    	fmt.Println(len(b)) // 6
    }
    

字符串格式化

  • 标准库FMT包中有很多字符串格式相关的方法
  • go语言中可以很轻松的用%v来打印任意类型的变量
  • package main
    import "fmt"
    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
    }
    

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

时间处理

package main
import (
	"fmt"
	"time"
)
func main() {
	now := time.Now()
	fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
	t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
	t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
	fmt.Println(t)                                                  // 2022-03-27 01:25:36 +0000 UTC
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
	fmt.Println(t.Format("2006-01-02 15:04:05"))                    // 2022-03-27 01:25:36
	diff := t2.Sub(t)
	fmt.Println(diff)                           // 1h5m0s
	fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
	t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
	if err != nil {
		panic(err)
	}
	fmt.Println(t3 == t)    // true
	fmt.Println(now.Unix()) // 1648738080
}

数字解析

  • 字符串和数字之间的转换
  • 使用strconv(string convert)
  • package main
    import (
    	"fmt"
    	"strconv"
    )
    func main() {
        //ParseFloat和ParseInt解析字符串
    	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
    	//Atoi把十进制字符串转成数字,itoA把数字转成字符串
    	n2, _ := strconv.Atoi("123")
    	fmt.Println(n2) // 123
        //输入不合法的情况
    	n2, err := strconv.Atoi("AAA")
    	fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
    }
    

进程信息

  • 使用os.argv来得到程序执行时指定的命令行参数
  • 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
    }