go语言基础语法详解 | 青训营

129 阅读9分钟

go语言基础语法

了解go语言

go是谷歌开发的一款编程语言,他相比于Java、c++等开发语言来说,go语言语法简单、编译快且轻

go语言优点

  1. 高性能、高并发
  2. 语法简单、学习曲线平缓
  3. 丰富的标准库
  4. 完善的工具链
  5. 静态链接
  6. 快速编译
  7. 跨平台
  8. 垃圾回收,也就是内存回收go语言会在进程结束时自动释放内存

go开发环境配置

基础语法

示例代码

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

go语言以main函数作为程序入口函数

fmt主要用于输入输出操作

编译&运行

运行指令

go run path

编译指令

go build path

会编译生成可运行文件通过./filename运行程序

变量

go中变量的声明可以使用var关键字加变量名进行声明,go会根据变量值自动匹配变量类型

变量声明

var variableName = value

var variableName typeName

var variableName1,variableName2 typeName = value1,calue2

variableName := typeName(value)

常量声明

const variableName = value

const variableName tepeName = value

示例代码

package main
​
import (
    "fmt"
    "math"
)
​
func main() {
    var a = "init"
    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 = "const"
    const h = 1024
    const i = 4e7 / h
    fmt.Println(s, h, i, math.Sin(h), math.Sin(i)) // Sin()为正弦函数
}

运行结果

image.png

分支结构之if-else

go语言的if语句与python类似,可以声明局部变量和进行表达式的运算

示例代码

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

运行结果

image.png

分支结构之switch

go语言的分支语句与c语言类似,但与c语言不同的是,go的case分支在结束时不需要使用break来结束case分支,则会自动跳出switch分支

并且go语言的switch语句使用也更加丰富,可以进行bool判断等

示例代码

package main
​
import (
    "fmt"
)
​
func main() {
    a := 2
    switch a {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
    case 3, 4:
        fmt.Println("three four")
    default:
        fmt.Println("other")
    }
​
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("It's before noon")
    default:
        fmt.Println("It's after noon")
    }
}

运行结果

image.png

循环for

go语言只有一种循环结构,就是for循环

并且go语言有多种for语法格式,可以不带参数,也可以像c语言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 + 3
    }
}

运行结果

image.png

数组

go语言数组与C语言类型,可以通过下标的方式访问数组元素,也可以创建多维数组

格式

var variableName [num1][num2]...typeName

示例代码

package main
​
import (
    "fmt"
)
​
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)
}

运行结果

image.png

切片

切片就像C++中的动态数组一样,数组的大小不是固定不变的,可以进行动态的添加和删除元素

可以使用make函数创建切片,也可以像python那样对数组进行切片操作

示例代码

package main
​
import (
    "fmt"
)
​
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 = append(s, "d") // 尾部添加
    s = append(s, "e", "f")
    fmt.Println(s)
​
    c := make([]string, len(s))
    copy(c, s)
    fmt.Println(c)
​
    fmt.Println(s[2:5])
    fmt.Println(s[:5])
    fmt.Println(s[2:])
​
    good := []string{"g", "o", "o", "d"}
    fmt.Println(good)
}

运行结果

image.png

map

go语言的map与c++的map容器 python的字典类似,都是对数据进行键值对的存储结构

map结构要通过make函数创建,通过delete函数删除map中的指定元素

示例代码

package main
​
import (
    "fmt"
)
​
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"])
​
    r, ok := m["unknow"] // 返回m中"unknow"对应的值,如果存在则ok为true否则为false
    fmt.Println(r, ok)
​
    delete(m, "one") // 删除map中one对应的元素
​
    m2 := map[string]int{"one": 1, "two": 2}
    var m3 = map[string]int{"one": 1, "two": 2}
    fmt.Println(m2, m3)
}

运行结果

image.png

函数

go语言函数的声明格式

func funName(形参变量名 typeName, ...) (返回值列表) {

return 返回值

}

go语言函数可以返回多个返回值,通常用多个返回值进行函数操作状态返回

示例代码

package main
​
import (
    "fmt"
)
​
func add(a int, 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)
​
    v, ok := exists(map[string]string{"a": "A"}, "a")
    fmt.Println(v, ok)
}

运行结果

image.png

指针

go语言内也存在指针的操作,但go语言的指针多数用于进行函数的传参

指针格式

variableName *typeName

示例代码

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)
    add2ptr(&n)
    fmt.Println(n)
}

运行结果

image.png

结构体

go语言与其他语言一样,也支持用户定义自己的变量类型,定义自己类型的属性和方法

格式

type variableName struct {

...

}

示例代码

package main
​
import (
    "fmt"
)
​
type user struct {
    name    string
    passwrd string
}
​
func checkPassword(u user, password string) bool {
    return u.passwrd == password
}
​
func checkPassword2(u *user, password string) bool {
    return u.passwrd == password
}
​
func main() {
    a := user{name: "wang", passwrd: "1234"}
    b := user{"wang", "1234"}
    c := user{name: "wang"}
    c.passwrd = "1234"
    var d user
    d.name = "wang"
    d.passwrd = "1234"
​
    fmt.Println(a, b, c, d)
    fmt.Println(checkPassword(a, "haha"))
    fmt.Println(checkPassword2(&a, "haha"))
}

运行结果

image.png

结构体方法

结构体方法就是结构体特有的函数,go语言中结构体方法不用在结构体中声明

格式

func (variableName structName) funName(形参变量名 typeName, ...) (返回值列表) {

...

}

示例代码
package main
​
import (
    "fmt"
)
​
type user struct {
    name    string
    passwrd string
}
​
func main() {
    a := user{name: "wang", passwrd: "1234"}
​
    fmt.Println(a.fCheckPassword("haha"))
    a.resetPassword("haha")
    fmt.Println(a)
}
​
func (u user) fCheckPassword(password string) bool {
    return u.passwrd == password
}
​
func (u *user) resetPassword(password string) {
    u.passwrd = password
}

运行结果

image.png

错误处理

go语言的错误处理基于errors静态库里的函数得以实现,一部分基于函数可以返回多个返回值的前提下更好的进行使用

示例代码

package main
​
import (
    "errors"
    "fmt"
    "math"
    "time"
)
​
type user struct {
    name    string
    passwrd 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") // new 创建errors防止函数返回释放局部变量
}
​
func main() {
    u, err := findUser([]user{{"wang", "1024"}}, "wang")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(u.name)
​
    if u, err := findUser([]user{{"wang", "1024"}}, "zhang"); err != nil {
        fmt.Println(err)
        return
    } else {
        fmt.Println(u.name)
    }
}

运行结果

image.png

字符串操作

strings头文件中也定义了很多好用的方法函数,用于对字符串进行操作

示例代码

package main

import (
	"errors"
	"fmt"
	"math"
	"strings"
	"time"
)

func main() {
	a := "hello"
	fmt.Println(strings.Contains(a, "ll")) // 返回字符串是否含有该子串
	fmt.Println(strings.Count(a, "l")) // 返回字符串中指定字符的个数
	fmt.Println(strings.HasPrefix(a, "he")) // 判断字符串是否以指定字符或字符串开头
	fmt.Println(strings.HasSuffix(a, "llo")) // 判断字符串是否以指定字符或字符串结尾
	fmt.Println(strings.Index(a, "ll")) // 返回子串在字符串中的索引,存在则返回子串的起始位置否则返回-1
	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // 拼接字符串
	fmt.Println(strings.Repeat(a, 2)) // 按指定次数,重复字符串,但不会改变原有的字符串
	fmt.Println(strings.Replace(a, "e", "E", -1)) // 按指定字符替换指定字符,最后一个参数为字符替换次数限制,-1则表示没有限制
	fmt.Println(strings.Split("a-b-c", "-")) // 按指定字符对字符串进行分割
	fmt.Println(strings.ToLower(a)) // 把字符串中大写字符替换为小写
	fmt.Println(strings.ToUpper(a)) // 把字符串中小写字符替换为大写
	fmt.Println(len(a))
	b := "你好"
	fmt.Println(len(b))
}

运行结果

image.png

字符串格式化

go也可以像c语言那样进行格式化输入输出,支持c语言的格式化操作符,也有新增的操作符%v可以对任意类型的数据进行输出

示例代码

package main

import (
	"errors"
	"fmt"
	"math"
	"strings"
	"time"
)

type point struct {
	x, y int
}

func main() {
	s := "hello"
	n := 123
	p := point{1, 2}
	fmt.Println(s, n)
	fmt.Println(p)

	fmt.Printf("s=%v\n", s)
	fmt.Printf("n=%v\n", n)
	fmt.Printf("p=%v\n", p)
	fmt.Printf("p=%+v\n", p) // 输出值对应的变量
	fmt.Printf("p=%#v\n", p) // 输出更详细的信息

	f := 3.1415926
	fmt.Println(f)
	fmt.Printf("%.2f\n", f)
}

运行结果

image.png

json处理

json为网络数据传输的一种格式,go语言支持这种格式的解析

json结构体要求各变量名开头字母大写

示例代码

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
	"time"
)

type userInfo struct {
	Name  string
	Age   int `json:"age"`
	Hobby []string
}

func main() {
	a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Go", "type"}}
	buf, err := json.Marshal(a) //对json数据进行编码
	if err != nil {
		panic(err) //结束程序运行
	}
	fmt.Println(buf)
	fmt.Println(string(buf))

	buf, err = json.MarshalIndent(a, "", "\t") // 对json数据进行缩进格式存储
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf))

	var b userInfo
	err = json.Unmarshal(buf, &b) //将json字符串转换为json结构体
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", b)
}

运行结果

image.png

时间处理

go语言也提供了一套完整的时间系统,用于时间方面的操作

示例代码

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
	"time"
)

func main() {
	now := time.Now() // 获取当前时间
	fmt.Println(now)
	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)
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
	fmt.Println(t.Format("2006-01-02 15:04:05")) // 格式化输出时间,参数为输出格式 2006-01-02 15:04:05为特定的时间格式化
	diff := t2.Sub(t) // 计算两个时间的相差值
	fmt.Println(diff)
	fmt.Println(diff.Minutes()/*分钟格式输出*/, diff.Seconds()/*秒格式输出*/)
	t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36") // 解析格式化字符串为时间,第一个参数为样式也是固定为2006-01-02 15:04:05
	if err != nil {
		panic(err)
	}
	fmt.Println(t3 == t)
	fmt.Println(now.Unix()) // 返回自1970-1-1日起到now代表时间以来的秒数
}

运行结果

image.png

数字解析

go语言也可以进行字符串转换为数字,数字转换为字符串的操作

示例代码

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

func main() {
	f, _ := strconv.ParseFloat("1.235", 64)
	fmt.Println(f)

	n, _ := strconv.ParseInt("111", 10, 64)
	fmt.Println(n)

	n, _ = strconv.ParseInt("0x1000", 0, 64) // 第二个参数可以设置进制,0则会自动匹配
	fmt.Println(n)

	n2, _ := strconv.Atoi("123")
	fmt.Println(n2)

	n2, err := strconv.Atoi("AAA")
	fmt.Println(n2, err)
}

运行结果

image.png

进程信息

go也提供函数对当前进程的信息进行输出

示例代码

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

func main() {
	fmt.Println(os.Args)
	fmt.Println(os.Getenv("PATH"))
	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))
}

运行结果

image.png

到这里go语言的基础语法部分就介绍完了