Go基础语法 | 青训营笔记

279 阅读6分钟

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

一、什么是Go语言:

1、高性能、高并发

2、语法简单、学习曲线平缓

3、丰富的标准库

4、完善的工具链

5、静态链接

6、快速编译

7、跨平台

8、垃圾回收

二、创建第一个Go项目:

第一步:go mod init xxx(任意名字)

第二步:创建一个xxx.go项目

第三步:在控制台输入 go run .\xxx.go 或者直接运行

例如我们输出一个helloword,首先通过上面3步创建一个go项目,然后代码如下

package main
import "fmt"

func main() {
    fmt.Println("helloword")
}

三、Go基础语法:

(1)go语言通过var来声明变量

1、可以直接通过var a=xxx 来声明变量,可以自动解析变量的类型

2、也可以通过var b int来确定变量类型

3、常量的声明:只需在前面添加const关键字即可,具体代码如下

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)
    fmt.Println(g)
    const s string = "constant"
    const h = 500000000
    const i = 3e20 / h
    fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}

(2)if-else的使用

相比较与java的if-else没有太多的变化,只是判断体不需要()

package main
import (
    "fmt"
)
func main() {
    if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is 0dd")
    }
    if 8%4 == 0 {
        fmt.Println("8 is divisible by 4")
    }
    if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multinle")
    }
}

(3)for的使用

for的使用跟java比较像,只是循环体没有在(),其他的理解跟java一样理解

package main
import (
    "fmt"
)
func main() {
    i := 1
    for {
        fmt.Println("loop")
        break
    }
    for j := 7; j < 9; j++ {
        fmt.Println(j)
    }
    for n := 0; n < 5; n++ {
        if n%2 == 0 {
            continue
        }
        fmt.Println(n)
    }
    for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }


}

(4)switch的使用

switch默认是不需要break跳出循环的,注意这点即可

package main


import (
    "fmt"
    "time"
)


func main() {
    a := 2
    //默认是不需要break跳出循环的
    switch a {
    case 1:
        fmt.Println(1)
    case 2:
        fmt.Println(2)
    case 3:
        fmt.Println(3)
    case 4, 5:
        fmt.Println(45)
    default:
        fmt.Println("other")
}
}

(5)数组与切片的使用

数组是长度一定的,而切片的长度是可以扩容的,所以我们在不确定数组的长度时最好用切片,而对于知道数组的最大长度,用数组也是可以的

数组的定义代码所示

func main() {
    var a [5]int
    a[4] = 100
    fmt.Println(a[4], len(a))
    b := [5]int{1, 2, 3, 4, 5}
    fmt.Println(b)
    var twoD [2][3]int
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d", twoD)
}

切片:切片是通过make关键字来创建的,详细请看代码注释

func main() {
    s := make([]string, 3)
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("get", s[2])
    fmt.Println("len", len(s)) //获取s的长度
    s = append(s, "d")         //添加一个
    s = append(s, "e", "f")    //添加两个
    fmt.Println(s)
    c := make([]string, len(s))
    copy(c, s) //将s中的值copy到c中
    fmt.Println(c)
    fmt.Println(s[2:5]) //输出下标为2到下标为4的值,即左闭右开
    fmt.Println(s[:5])  //输出5个
    fmt.Println(s[2:])  //从下标为2的开始输出
    good := []string{"g", "o", "o", "d"}
    fmt.Println(good)


}

(6)map的使用

map是存储键值的数据,它可以通过声明来确定存储k,v的类型,该结构常用于1对1数据时,通过键值存储来达到数据的绑定

func main() {
    m := make(map[string]int)
    m["one"] = 1
    m["two"] = 2
    fmt.Println(m)
    fmt.Println(len(m))
    fmt.Println(m["one"])
    fmt.Println(m["unknow"]) //0
    r, ok := m["unknow"]//检查是否存在这个key
    fmt.Println(r, ok) //0 false
    delete(m, "one")
    m2 := map[string]int{"one": 1, "two": 2}
    var m3 = map[string]int{"one": 1, "two": 2}
    fmt.Println(m2, m3)
}

(7)遍历-range

对存储数据的结构进行遍历的函数,具体看代码即可

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) //0,2
        }
    }
    fmt.Println(sum) //9
    m := map[string]string{"a": "A", "b": "B"}
    //键值遍历
    for k, v := range m {
        fmt.Println(k, v) //b 8;a A
    }
    //键遍历
    for k := range m {
        fmt.Println("key", k) //key a;key b
    }


}

(8)函数 函数是我们最常用的,与java的方法相似,通过声明函数的参数类型、返回值等来构建函数,函数的作用就是使代码简洁,让学习的人一看就明白,也可以减少代码的重复

// 参数 类型 返回值
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.Print(v, ok) //A True


}

(8)指针

传入的参数分为两种:1、值传递 2、地址传递,而指针则是地址传递,它是传入该参数的地址,修改时参数传入的参数也会被修改,而值传递不会修改传入的参数的值

// 参数 类型 返回值
func add2(a int) {
    a += 2
}
func add2ptr(a *int) {
    *a += 2
}
func main() {
    n := 5
    add2(n)
    fmt.Println(n)//5
    add2ptr(&n)
    fmt.Println(n)//7


}

(8)结构体和结构体方法

结构体就是声明一个实体类一样的思想,将各种参数的类型以及id声明在结构体内,便于更好的封装。

结构体方法也区别指针和值传递,跟函数类似

type user struct {
    name     string
    password string
}


func main() {
    a := user{name: "wang", password: "1024"}
    a.checkPassword2("2048")
    fmt.Println(a.checkPassword("2048"))


}
func (u user) checkPassword(password string) bool {
    return u.password == password
}
func (u *user) checkPassword2(password string) {
    u.password = password
}

(9)错误处理

可以自己创建一个函数来处理错误,使错误更具有识别性

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

(10)字符串格式化,时间格式

这个没有太多思想,观看代码即可

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("s=%v\n", n)  //s=123
	fmt.Printf("s=%v\n", p)  //s={1 2}
	fmt.Printf("s=%+v\n", p) //s={x:1 y:2}
	fmt.Printf("s=%#v\n", p) //s=main.point{x:1, y:2}
	f := 3.141592653
	fmt.Println(f)          //3.141592653
	fmt.Printf("%.2f\n", f) //3.14

}

package main


import (
    "fmt"
    "time"
)


func main() {
    now := time.Now()
    fmt.Println(now) //2023-01-15 17:23:58.5944814 +0800 CST m=+0.005750801
    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()) //1673774638


}

(11)数字解析

数字解析可以有利于我们对string类型和int以及其他的数据之间的转换,可以设置精度以及进制,方便于对类型的转换

package main


import (
    "fmt"
    "strconv"
)


func main() {
    f, _ := strconv.ParseFloat("1.234", 64)
    fmt.Println(f) //1.234
    //字符串 10:进制 返回64位的精度
    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


}