青训营笔记之Go语言基础语法 | 豆包MarsCode AI 刷题

93 阅读6分钟
变量var

go 是一种强变量类型的语言,常见的数据类型包括bool型、int型、float型等

有两种变量声明方式:

① var name (*) = ** -- var + 变量名 + 变量类型 + = + 初始化的值
(变量类型可以不写,而是自动推导)
(可以不用手动初始化,直接 var + 变量名 + 变量类型 使用默认初始化)
② 使用 变量 := 值 -- 变量名 + := 值
如 f := float32(x)

注意:go中const变量的具体变量类型,如果不给出,也是可以通过自动推导得到(和C/C++不同)

遍历 for

go 不存在 while 循环,只有这一种简单的 for 循环,同样三段,但不需要类似 C/C++ 那样添加括号

for j := 7; j < 9; j++ {
    fmt.Println(j)
}
条件判断 if

同 C/C++ 一样,但是不需要加括号,而且必须跟花括号,不能没有花括号写在一行

num := 9
if num < 0 {
    fmt.Println(num, "is negative")
} else if num < 10 {
    fmt.Println(num, "has 1 digit")
} else {
    fmt.Println(num, "has multiple digits")
}
条件判断 switch

同 C/C++ 一样,但是首先 switch 紧接着的判断不用加括号,其次每个 case 可以不用写break来表示结束,执行完一个 case 就结束,这里和 C/C++ 继续跑完后面所有的 case 是不同的

a := 2
switch a {
case 1:
    fmt.Println("one")
case 2:
    fmt.Println("two")
case 3:
    fmt.Println("three")
case 4, 5:
    fmt.Println("four or five")
default:
    fmt.Println("other")
}
静态数组 array

因为长度固定,所以需要注意定义方式

var a [5]int
var b [2][3]int
c := [5]int{1, 2, 3, 4, 5}
动态切片 slice

注意动态切片的创建方法,通过 make 来创建切片,而且创建的动态切片可以像 python 一样支持切片操作,只不过不可以接受负值索引,slice原理是存储了一个长度、容量、指向数组的指针,可以参考 STL 中的 vector,当长度超过容量时,也会发生扩容,从而返回一个指向新数组的指针

s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
s = append(s, "d")
s = append(s, "e", "f")

c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5])  // [a b c d e]
fmt.Println(s[2:])  // [c d e f]

good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
字典 map

本身存储 key 是无序的,参照 STL 中的 unordered_map,注意定义方式即可

m := make(map[string]int)
m["one"] = 1
m["two"] = 2

r, ok := m["unknow"]

delete(m, "one")

m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
遍历 range

主要用于遍历数组和 map 时可以迅速遍历,比如对于数组可以得到索引以及索引所在的值,对于 map 可以得到键值对 key-value

nums := []int{2, 3, 4}
for i, num := range nums {
    ***
}

m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
    ***
}

for k := range m {
    ***
}
函数 func

注意定义的方式,参数类型,返回类型,这些类型都是后置的

golang里面的函数原生支持多个返回值,真正的业务逻辑中一般函数都包含2个返回值,一个是真正的函数返回值,一个是错误信息

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
}
指针 point

和 C/C++ 使用方法类似,使用 & 获取指针对象,使用 * 解引用操作具体存储的值

结构体 struct

定义和 C/C++ 使用方法类似,定义方法注意类型后置

type user struct {
    name     string
    password string
}

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"

结构体方法和 C/C++ 存在差异,方法定义时需要指定具体结构体作为参数,其实类似于C++中的类的成员函数

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
}
错误处理 error

可以在函数定义中,返回值加上 error,在函数体中出现异常的情况就通过 error 返回,在外部可以通过简单的 if-else 进行错误的排查定位

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")
}
字符串操作 string

知道一些常用的函数即可,和 python 类似

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

字符串格式化,对比 C 标准库中 printf 函数的使用,注意可使用 %v 来忽略格式打印,使用 +v/#v 来得到更详细内容

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

对于已有的结构体,可以直接使用 json.marshal 进行序列化,序列化之后产生 Byte 数组,字符串表示就是一个 json 字符串,其中默认序列化之后的字符串风格是大写字母开头,而不是下划线或者小写开头,如果有类似需求,可以在结构体对应字段后面加上 json tag 来修改默认序列化风格。同样的,反序列化是将 Byte 数组变为原始结构体数据,使用json.Unmarshal 函数实现

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"}}
}
时间处理 time

了解时间常用的函数即可

time.Now() // 获取当前时间
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC) // 构造时间
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 获取时间具体某个值
fmt.Println(t.Format("2006-01-02 15:04:05")) // 按照给定格式输出时间
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
diff := t2.Sub(t) // 计算时间间隔,默认为年月日时分秒
fmt.Println(diff.Minutes(), diff.Seconds()) // 统一为分,统一为秒
t, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36") // 按照格式(前者)将对应时间(后者)构造新的时间对象
fmt.Println(t1 == t2) // 比对时间
now.Unix() // 获取时间戳
数字解析 strconv

了解常用的一些字符串到基础数据类型的转换即可

f, _ := strconv.ParseFloat("1.234", 64)
n, _ := strconv.ParseInt("111", 10, 64)
n, _ = strconv.ParseInt("0x1000", 0, 64)
n2, _ := strconv.Atoi("123")
进程信息 env
fmt.Println(os.Args) // 获取运行时的参数
fmt.Println(os.Getenv("PATH")) // 获取系统环境变量 PATH 信息
fmt.Println(os.Setenv("AA", "BB")) // 设置环境变量 AA = BB
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput() // 执行命令得到输出