Go语言基础入门 | 青训营

166 阅读10分钟

Go语言的优点

  • 高性能、高并发
  • 语法简单、学习曲线平缓
  • 丰富的标准库
  • 完善的工具链
  • 静态链接
  • 快速编译
  • 跨平台
  • 垃圾回收

Go语言基础语法

Hello World

参看如下代码

package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

package main 表示一个特殊的包(package),每个源代码文件都必须属于某个包,而 main 包是用于构建可执行程序的入口包。当你创建一个可执行程序时,需要在其中一个 Go 源代码文件的顶部使用 package main 声明。这个包中的 func main() 函数会被视为程序的入口点,也就是当你运行程序时,操作系统会从这个函数开始执行,即该程序的入口函数。

import "fmt" 是用来导入 Go 语言标准库中的 fmt 包。在 Go 中,import 语句用于引入其他包,以便你可以在自己的代码中使用这些包中定义的函数、类型和变量。在上述代码中,fmt 包提供了格式化输入和输出的功能,包括打印到标准输出、格式化字符串、处理输入等。通过导入 fmt 包,你可以使用 fmt.Println 函数来在控制台输出文本。

值得一提的是, package 后面跟的不一定是 main,也可以自己创建一个包,包名称的选择应该遵循一些约定:

  1. 包名应该是简短、有意义的,通常采用小写字母,避免使用短语和缩写;
  2. 包名不应该与标准库中的包名冲突;
  3. 对于可执行程序的入口包,通常使用 package main

然后在自己定义的包中可以实现一些功能,其他文件可以通过导入这个包来使用其功能。例如,你可以创建一个名为 utils 的包:

package utils

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

然后在其他文件中可以通过导入这个包来使用它的函数:

package main

import (
    "fmt"
    "yourmodule/utils"
)

func main() {
    sum := utils.CalculateSum(10, 20)
    fmt.Println("Sum:", sum)
}

常量与变量

常见的常/变量类型有以下四种:

  • 字符串

    Go 语言中的字符串属于内置类型,可以直接拼接,也可以直接用关系运算符比较;

  • 整型

  • 浮点型

  • 布尔型

值得注意的是常量与变量都可以不确定类型,由上下文自动确定类型。

另外,在用 fmt.Println() 打印多个变量的值时,中间会使用空格作为间隔。

if else

与 C++ 中类似,但是有以下几点不同:

  1. 判定条件可以不用加括号,即使有也不报错,只是会自动忽略罢了;
  2. 判定条件可以不只一句,可以加上变量声明,不同句之间以分号隔开;
  3. 执行内容部分的代码必须要用大括号括起来,即使只有一行也是如此。

for循环

Go 语言中只有for一种循环,语法与 C++ 类似,在 Go 语言中 C++ 的经典三段式for循环可以忽略其中的任意段,最简单的是什么都不写的死循环。

switch语句

Go 语言中的switch语句也与C++类似,最大的不同点在于C++在匹配成功之后如果不加break会继续向下跑完所有的情况,但是Go语言不会。另外,Go 语言的switch更加强大,变量类型可以任意,也可以不加变量在case里写条件分支,替代if else语句。

数组

需要注意的是,在 Go 语言中直接输出数组名会得到该数组,而非像 C++ 那样的首元素。

另外,获取数组,切片,映射及字符串长度的函数 len() 是定义在内建的 builtin 包中,会自动导入而无需显式导入,直接使用即可。

切片

在实际应用中其实切片用得比数组更多,个人理解切片就像可以任意改变长度的数组一样,可以用 make() 函数来创建一个切片,也可以用 append() 函数来追加切片元素,容量不够则会扩容,具体的扩容机制详见 www.jb51.net/jiaoben/292…

另外,切片/数组也支持索引操作。

map

本质上就是键值对的集合,Go 语言中的map是完全无序的,遍历时是按照随机顺序的,可用 make 函数或声明创建,用delete删除键值对,不存在的键的值默认为0。

另外,用map中的键对应的值进行赋值是有两个返回值的,第一个值是该键的值,第二个值是bool型的,用于判断该键是否存在,若存在返回 true,不存在则反之。

range

range可以用来快速遍历数组,切片,map或是结构体,常与for循环搭配使用,返回键与值,如不需要可以用下划线或者省略不写来忽略。

函数

简单提一句,Go 语言中函数返回值变量可以在函数原型处进行定义,当函数体的 return 后面没有指定函数的返回值时则依照函数原型中定义的返回值变量进行返回,否则 return 后的返回值会将其覆盖。

指针

Go 语言指针支持的操作十分有限,主要用于对传入的参数进行修改。

结构体及其方法

本质上就是把字段封装在一个特定的类型里,可以加之以方法(实现特定功能的函数)。同样地,要修改结构体变量必须是结构体指针变量的方法,而不是结构体变量的方法。

错误处理

在 Go 语言中,函数返回 error 类型的值是一种常见的方式,用于处理函数执行过程中可能发生的错误情况。这种机制允许函数在出现错误时提供有关错误信息,并且调用函数的代码可以根据这些信息来决定如何处理错误。

字符串操作

对于字符串的操作,Go语言有一个专门的 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,第四个参数代表替换的次数,-1即替换所有匹配项,并不对原字符串进行修改,而是返回新的字符串
	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,一个中文3个字节
}

字符串的格式化输出

fmt 包里有很多有关输出的函数,fmt.Println() 只是其中一种,意为“输出后换行”,另外还有 fmt.Printf() 函数,和 C++ 里的类似,支持格式化的输出,可以使用%v来打印各种类型的变量,%+v%#v 则更加详细,后者比前者更详细。

JSON处理

在 Go 语言中,JSON 处理是指使用内置的 encoding/json 包来进行 JSON 数据的编码和解码操作。JSON 是一种轻量级的数据交换格式,常用于在不同的应用程序之间传递和存储数据。

Go 语言的 encoding/json 包提供了一组功能,允许你将 Go 数据结构与 JSON 数据之间进行转换。你可以使用这个包来:

  • 将 Go 的数据结构编码为 JSON 格式的数据,用于传输或存储。
  • 将 JSON 格式的数据解码为 Go 的数据结构,以便在代码中进行处理。

谈到 JSON 处理,就不得不谈到结构体字段的标签。结构体标签是附加到结构体字段后面的字符串,用于为结构体字段提供元数据。在 JSON 编码和解码时,这些标签可以用来指定字段在 JSON 数据中的名称、编码规则等信息。

在 JSON 编码和解码过程中,encoding/json 包会读取结构体标签来决定如何处理结构体字段。例如,json:"name" 中的 "name" 用于指定结构体字段在 JSON 数据中的名称。如果不提供这个标签,encoding/json 包会默认使用字段的名字作为 JSON 键值。

时间处理

在 Go 语言中,与时间处理相关的函数定义在 time 包里,具体注释见如下代码:

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()                                   //获取本地时间,包括年月日时分秒及纳秒,+0800 CST即中国标准时间(东八区、北京时间)
	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) //time.UTC将时间设置为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,输出Unix时间戳,即1970-01-01 00:00:00到现在的秒数
}

数字解析

同样还是懒得写所以上代码啦~

package main

import (
	"fmt"
	"strconv"
)

func main() {
	f, _ := strconv.ParseFloat("1.234", 64) //将字符串转化为float64类型
	fmt.Println(f)                          // 1.234

	n, _ := strconv.ParseInt("111", 10, 64) //将字符串转化为int64类型,第二个参数代表进制
	fmt.Println(n)                          // 111

	n, _ = strconv.ParseInt("0x1000", 0, 64) //第二个参数为 0 则由系统根据前缀自行判断进制
	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

	value := 12345
	n3 := strconv.Itoa(value) //将整型转化为字符串,只有一个返回值
	fmt.Println(n3)
}

进程信息

os.Args 是一个字符串切片,包含了程序在命令行中传递的参数,第一个元素是程序的名称,之后的元素是传递给程序的参数。在运行程序时可以在命令行中传递参数,例如:

$ go run main.go arg1 arg2 arg3

在这个例子中,os.Args[0] 将会是 "main",os.Args[1] 将会是 "arg1",os.Args[2] 将会是 "arg2",依此类推。

os.Getenv() 获取特定名称的环境变量的值。如果该环境变量存在并且有值,那么将返回环境变量的值。如果环境变量不存在或者没有值,将返回一个空字符串。

os.Setenv() 是 Go 语言中用于设置环境变量值的函数,接受一个环境变量的名称和要设置的值作为参数,返回一个错误。需要注意的是,通过 os.Setenv() 设置的环境变量只会在当前程序的运行时生效,不会影响到其他正在运行的程序。

在 Go 语言的 os/exec 包中,CombinedOutput()Cmd 类型的方法,用于执行外部命令并获取其标准输出和标准错误的合并输出。Cmd 表示一个外部命令对象,通过 exec.Command() 函数创建。CombinedOutput() 方法执行这个命令,并返回一个字节数组,其中包含了命令的标准输出和标准错误的合并内容。