Go语言基础语法 | 青训营笔记

121 阅读9分钟

笔记1.webp

Go语言介绍:

Go语言的特点

  1. 高性能、高并发
  2. 语法简单
  3. 有丰富的标准库
  4. 工具链完善
  5. 静态链接
  6. 快速编译
  7. 跨平台
  8. 垃圾回收

Go(又称Golang)是Google公司开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go使用编译器来编译代码。编译器将源代码编译成二进制(或字节码)格式;在编译代码时,编译器检查错误、优化性能并输出可在不同平台上运行的二进制文件。

基本语法

Hello World

先运行最简单的Hello World:

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

变量

go语言是一门强类型语言。

常见的变量类型:字符串、整数、浮点型、布尔型。

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

if else

go语言的if else 的if后面必须跟上大括号。

举个例子:

package main  
  
import "fmt"  
  
func main() {  
  
    if 7%2 == 0 {  
        fmt.Println("7 is even")  
    } else {  
        fmt.Println("7 is odd")  
    }  
  
    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 multiple digits")  
    }  
}

switch

go语言的switch判断有些不同,Java必须使用break跳出语句,而go语言的不使用。

语法:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  

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

循环

go语言的循环语句只有for。

语法:

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

数组

语法:

  1. var a [5]int //语法1 定义但不赋值 a[4] = 100 //赋值
  2. b := [5]int{1, 2, 3, 4, 5} //语法2 定义并赋值
  3. var twoD [2][3]int //语法3:二维数组
package main  
  
import "fmt"

func main() {  
  
    var a [5]int  //语法1 定义但不赋值
    a[4] = 100  //赋值
    fmt.Println("get:", a[2])  
    fmt.Println("len:", len(a))  

    b := [5]int{1, 2, 3, 4, 5}  //语法2 定义并赋值
    fmt.Println(b)  

    var twoD [2][3]int  //语法3:二维数组
    for i := 0; i < 2; i++ {  
        for j := 0; j < 3; j++ {  
        twoD[i][j] = i + j  
        }  
    }  
    fmt.Println("2d: ", twoD)  
}

切片

切片可以改变长度, 取值和数组一样,用append追加元素,不支持负数索引。

语法:

package main  
  
import "fmt"  
  
func main() {  

    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))  
    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

实际使用过程中最频繁用到的数据结构,键值对的形式,可以用delete删除键值对,无序。

语法:

    m := make(map[string]int)  //定义map
    m["one"] = 1  //以键值对的形式给map赋值
    m["two"] = 2  
    fmt.Println(m) // map[one:1 two:2]  
    fmt.Println(len(m)) // 2  
    fmt.Println(m["one"]) // 1  
    fmt.Println(m["unknow"]) // 0  

    r, ok := m["unknow"]  
    fmt.Println(r, ok) // 0 false  

    delete(m, "one")  //删除键为one的值,删除的是键值对

    m2 := map[string]int{"one": 1, "two": 2}  
    var m3 = map[string]int{"one": 1, "two": 2}  
    fmt.Println(m2, m3)

range

用于遍历,遍历数组时返回两个值,第一个值为索引,第二个值为对应的值,如果不需要索引,可以用下划线来忽略。 语法:

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

函数

变量类型后置,如a int,int类型的变量a

Golang里面的函数原生支持返回多个值,实际业务逻辑代码里面几乎所有函数都返回两个值,第一个值是真正的返回值,第二个值是一个错误信息。

语法:

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  
}

指针

主要用途是对于传入的参数进行修改。语法:

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  
}

结构体

结合体就是带类型的字段的集合。

结构体支持指针。 语法:

type user struct {  //定义对象
    name string  
    password string  
}  
  
func main() {  
    //定义三个user对象,定义的同时赋值
    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  
}

结构体方法

Golang中可以为结构体定义一些方法。

有两种写法,一种是带指针的,即可以对结构体进行修改的;另一种是不带指针的,实际上就是一个拷贝的操作,无法对结构体进行修改。 语法:

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 语言里面符合语 惯的做法就是使 单独的返回值来传递错误信息 不同于 Java 自家家使用的异 0o语言的处理产 够很清晰地知道哪个函数返回了错误 并且能用简单的ifelse 来处理错误。

在函数里面,我们可以在那个函数的返回值类型 面加一个error.就代表这个数口反回错 那么在函数实现的时候,retum 需要同时return两个值,要么就是如果出现错误的话,那么可以return nil和一个error。如果没有的话,那么返回原本的结果和nil。

语法:

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包里面有很多常用的字符串工具函数

比如 :

  • contains 判断一个字符电里面是否有包含另一个字符申
  • count 字符串计数,index查找某个字符串的位置
  • join连战 接多个字符串
  • repeat 重复多个字符串
  • replace 替换字符串。

语法:

    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包里面有很多的字符串格式相关的方法

比如 printf这个类似于语言里面的punt函数。不同的是,在go语言里面的话,你可以很轻松地用%v来打印任意类型的变量而不需要区分数字字符串。你也可以用%+v打印详细结果,%#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  
}

JSON处理

对于一个已有的结构体,我们可以什么都不做,只要保证每个字段的第一个字母是大写,也就是是公开字段。那么这个结构体就能用JSON.marshaler去序列化,变成一个JSON的字符串。

序列化之后的字符串也能够用JSON.unmarshaler去反序列化到一个空的变量里面。

这样默认序列化出来的字符串的话,它的风格是大写字母开头,而不是下划线。我们可以在后面用json tag等语法来去修改输出JSON结果里面的字段名。

语法:

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.Now() 获取当前时间

time.Date() 构造一个带时区的时间

Year(),Month(),Day(),Hour(),Minute(),Seconds() 获取该时间点的年月日时分秒

sub(Date) 对两个时间进行减法,得到一个时间段。

UNIX() 获取时间戳

语法:

    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

数字解析

字符串和数字之间的转换。

STR conv(string convert)包

可以用parseInt或parseFloat解析字符串,parseint参数

可以用Atoi把一个十进制字符串转成数字,用itoA把数字转换成字符串

如果输入不合法,这些函数会返回error

语法:

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

进程信息

用os.argv来得到程序执行的时候指定的命令行参数,用so.getenv读取环境变量

语法:

// 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

总结

Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。Go支持面向对象,而且具有真正的闭包(closures)和反射 (reflection)等功能。

Go 语言语法与 C 相近,但功能上有:内存安全,GC,垃圾回收,结构形态及 CSP-style 并发计算

以上就是我整理的go语言基础语法,目的是用来复习go语言,仅供参考,感谢阅读!!!