Go 语言入门笔记 | 豆包MarsCode AI刷题

42 阅读9分钟

Go 环境准备

本文主要讲解的是在windows上安装Go语言的环境和配置环境变量

下载 Go 环境

  1. 首先到 Go 的官网找到想要的版本下载
  2. 放到自己定义的目录下,然后解压

配置环境变量

得到完整的 Go 环境之后,需要配置 Go 的环境变量,右击此电脑–>属性–>高级系统设置–>环境变量,打开环境变量设置窗口。

需要新建两个环境变量配置

一个是 GOROOT ,这个就是 Go 环境所在目录的配置。

另一个是 GOPATH ,这个是 Go 项目的工作目录,你以后开发的代码就写在这个文件夹中。

GOROOT 环境变量配置

1、为了使所有的计算机用户都可以使用 Go 环境,我们就在系统变量之中配置。点击系统变量下的新建,在变量名一栏输入 GOROOT ,在变量值一栏输入你解压文件所在的目录。最后点击确定,就将 GOROOT 新建完毕。

2、然后将新建的GOROOT配置到 Path 这个环境变量中去,在系统变量中找到 Path,点击编辑->新建,输入%GOROOT%\bin,点击确定。并将所有母窗口的确定全部点下,确保环境变量生效。

GOPATH环境变量配置

GOPATH 和 GOROOT 的配置略有不同,建议配置两个GOPATH 目录,第一个用于放 Go 语言的第三方包,第二个用于放自己的开发代码。

点击系统变量下的新建,在变量名一栏输入GOPATH,在变量值一栏输入任意两个目录,中间用英文分号隔开。

示例:D:\go\library;D:\go\workspace

检验配置

windows+R 输入 cmd 打开终端,输入go version,如果输出如下图所示,则安装成功。

#查看Go版本
go version

#查看Go环境变量
go env

Go 基础语法

Go 特点

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

如 Go 只需要十行代码就能实现一个 HTTP 服务器

package main

import (
    "net/http"
)

func main() {
    http.Handle("/", http.FileServer(http.Dir(".")))
    http.ListenAndServe(":8080", nil)
}

基础语法

数据类型

在 Go 编程语言中,数据类型用于声明函数和变量。

数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。

Go 语言按类别有以下几种数据类型:

变量声明

  1. 使用关键字var来声明一个变量,语法为:var variableName dataType
  2. 变量名必须以字母或下划线开头,可以包含字母、数字和下划线,但不能使用Go的关键字。
  3. 可以一次性声明多个变量,例如:var x, y int
  4. 如果声明时未初始化变量,则变量会被赋予其数据类型的零值,比如:int类型的零值是0,string类型的零值是空字符串""。
  5. 可以使用短变量声明来创建并初始化变量,语法为:variableName := value
  6. 在Go中,变量声明后必须使用,否则会导致编译错误。如果想要声明一个变量但不使用它,可以使用下划线 _ 来代替变量名,表示该变量被丢弃,不会占用内存空间。
# 方式一
var a = "initial"
var a int = 2
# 方式二
f := 1

常量声明

  1. 使用关键字const来声明常量,语法为:const constantName dataType = value
  2. 常量的值在声明时必须初始化,并且一旦赋值不能再修改。
  3. 常量可以是字符、字符串、布尔值或数值类型(整数、浮点数)。
  4. 常量名的命名规则与变量相同,以字母或下划线开头,可以包含字母、数字和下划线,但不能使用Go的关键字。
  5. 常量的值必须是一个编译时可以确定的表达式,例如:const PI = 3.14
  6. 常量必须在声明时初始化,并且其值在程序运行期间不能改变。
const a = 1
const s string = "constant"

条件语句

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

循环语句

Go 里面只有 for 循环

for {
    fmt.Println("loop")
    break
}

for i := 1; i < 9;i++ {
    fmt.Println(i)
}

i := 1
for i <= 3 {
    fmt.Println(i)
    i = i+1
}

switch

Go 中 switch 在执行完某个 case 之后会直接退出,不需要使用 break

func main() {
    a:=2
    switch a {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
    case 3 ,4:
        fmt.Println("three or four")
    default:
        fmt.Println("other")  
    }

    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("it is before noon")
    default:
        fmt.Println("it is after noon")
    }
}

数组

数组长度固定在真实的业务场景下不常用

var a [5]int
a[4] = 2

b := [5]int{1,2,3,4,5}

var twoD [2][3]int

切片 slice

切片长度可变,常用于真实业务场景下

s := make([]string, 2)
s[0] = "a"
s[1] = "b"
fmt.Println("len:", len(s)) // 2

s = append(s, "c")
s = append(s, "d", "e")
fmt.Println(s) // [a b c d e]

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

fmt.Println(s[2:4]) // [c d]
fmt.Println(s[:4]) // [a b c d]
fmt.Println(s[2:]) // [c d e]

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

map

实际开发中使用最频繁的数据结构,放入 map 的数据完全无序

m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(lem(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unkonw"]) // 0

# ok 用于接收 map 中是否有该 key
r, ok := m["unkonw"]
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}

range

主要用于简化遍历过程

nums := []int{1,2,3,4}
sum := 0
for i, num := range nums {
    sum += num
    fmt.Println(i)
}
for _, num := range nums {
    sum += num
}


m := map[string]string{"a":"A", "b":"B"}
for k, v := range m {
    fmt.Println(k, v) // b B;a A
}
for k := range m {
    fmt.Println("key", k) // key a;key b
}

函数 func

在实际的业务逻辑代码中,函数返回多个值,第一个值为真实返回值,第二个为错误信息

# 函数名 参数 返回值类型
func add(a int, b int) int {
    return a + b
}

func add(a, b int) int {
    return a + b
}

 func exist(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 := exist(map[string]string{"a":"A"}, "a")
    fmt.Println(v, ok) // A True
}

指针 point

Go 初步支持指针,但相比于 C 或 C++,其支持的操作非常有限

func add2(n int) {
    n += 2
}

func add2ptr(n *int) {
    *n += 2
}

func main() {
    n := 2
    add2(n)
    fmt.Println(n) // 2
    add2ptr(&n)
    fmt.Println(n) // 4
}

结构体

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
}

结构体方法

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 中常使用一个单独的返回值来传递错误信息,不同于Java中的异常,Go 语言能够很清晰的知道哪个函数返回了错误,可以用简单的 if-else 来处理错误,出现错误返回值和错误信息,没有错误返回值和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
}

字符串格式化

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}

    // 不管什么类型都是使用 %v,可以通过加 +、# 得到更详细的输出
	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 处理时要保证结构体每个字段首字母大写

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

时间处理

Go 中最常用的时间处理函数是 time.Now() 获取当前时间

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
}

数字解析

字符串与数字之间的转换

package main

import (
	"fmt"
	"strconv"
)

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

    // ParseInt 参数1 字符串 参数2 进制(0的话自动推测) 参数3 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
}

进程信息

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
}