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

94 阅读25分钟

一、简介

1.1 什么是 Go 语言

Go 语言是一种由 Google 公司开发的开源编程语言,简洁、高效、并行多核编程和网络编程支持是其设计的主要特点。Go 语言具有类似 C 语言的语法结构,又提供了更强大的类型系统、包管理、垃圾回收等高级特性。Go 语言广泛用于云计算、大数据处理、分布式系统以及网络编程等领域。

1.2 哪些公司在使用 Go 语言

ByteDance、Google、Tencent、Facebook、美团、七牛云、滴滴、Bilibili、百度、PingCAP ……

1.3 字节跳动为什么全面拥抱 Go 语言

  1. 最初使用的 Python,由于性能问题换成了 Go
  2. C++ 不太适合在线 Web 业务
  3. 早期团队非 Java 背景
  4. 性能比较好
  5. 部署简单、学习成本低
  6. 内部 RPC 和 HTTP 框架的推广

二、入门

2.1 开发环境

2.1.1 安装 Golang

  1. go.dev/
  2. studygolang.com/dl
  3. goproxy.cn/

2.1.2 配置集成开发环境

  1. Visual Studio Code 由Microsoft开发,免费
  2. GoLand 收费但可以通过学校邮箱免费使用

2.2 基础语法

2.2.1 Hello World

fmt.Println("Hello World")

2.2.2 变量

在Go语言中,变量是程序中最基本的存储单元之一。每个变量都有一个类型和一个值,变量的类型用于定义其可以存储的值的范围和操作。变量的值可以随时更改,因此Go语言中的变量是可变的。 在Go语言中定义变量的语法如下:

var 变量名 数据类型

其中,var是关键字,后面跟着变量名和数据类型。数据类型可以是内置类型,如int、float、bool等,也可以是自定义类型。以下是一些常见的变量定义示例:

var x int // 定义一个整数变量
var y float32 // 定义一个浮点型变量
var z string // 定义一个字符串变量
var a, b, c bool // 定义三个布尔型变量

在Go语言中,还可以使用短变量声明语法来快速定义变量并初始化。其语法如下:

变量名 := 值

以下是使用短变量声明语法定义变量的示例:

x := 10 // 定义一个整数变量并初始化为10
y := 3.14 // 定义一个浮点型变量并初始化为3.14
z := "Hello, world!" // 定义一个字符串变量并初始化为"Hello, world!"
a, b, c := true, false, true // 定义三个布尔型变量并初始化为true、false、true

需要注意的是,短变量声明语法只能用于函数内部,而无法用于全局变量的定义。

2.2.3 if else

在Go语言中,if...else语句用于控制程序执行流程,根据指定的条件来判断程序应该执行哪段代码块。其基本语法如下:

if condition {
    // 在条件成立时执行的语句块
} else {
    // 在条件不成立时执行的语句块
}

其中,condition是一个可以返回truefalse结果的表达式。如果condition的结果为true,则会执行if后面的语句块;否则,会执行else后面的语句块。 以下是使用if...else语句的示例:

package main

import "fmt"

func main() {
    x := 10
    y := 20

    if x > y {
        fmt.Println("x is greater than y")
    } else {
        fmt.Println("y is greater than x")
    }
}

在这个示例中,我们定义了两个变量xy,并通过if...else语句来比较它们的大小。由于x的值小于y的值,因此程序会输出“y is greater than x”。 在实际编程中,if...else语句常用于处理分支逻辑,例如检查用户输入是否合法、判断某个条件是否成立等。 除了基本的if...else语句外,Go语言还提供了其他一些语法结构来进行条件判断。例如,可以使用if语句来判断某个变量是否是某种类型的实例:

package main

import "fmt"

func main() {
    var x interface{} = 10

    if _, ok := x.(int); ok {
        fmt.Println("x is an integer")
    } else {
        fmt.Println("x is not an integer")
    }
}

在这个示例中,我们定义了一个名为x的接口类型变量,并使用if语句来检查该变量是否是一个整数。由于x的值是整数类型,因此程序会输出“x is an integer”。

2.2.4 循环

在Go语言中,循环用于重复执行相同的代码块,直到满足特定条件为止。Go语言提供了多种循环语句,包括forwhiledo...while等。其中,for语句是最常用的循环语句。 for 循环 for语句用于执行一系列语句,直到指定的条件不再成立为止。其基本语法如下:

for initialization; condition; post {
    // 在条件成立时执行的语句块
}

其中,initialization是在循环开始前执行一次的语句,通常用来初始化计数器等变量;condition是一个可以返回truefalse结果的表达式,用来判断循环是否继续执行;post是在循环每次迭代后执行的语句,通常用来更新计数器等变量的值。 以下是使用for循环的示例:

package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Println("i is", i)
    }
}

在这个示例中,我们使用for循环输出04的数字。由于循环条件i < 5成立,因此程序会一直执行循环体,直到i的值变为5时停止。 除了基本的for循环语句外,Go语言还提供了for range语句用于遍历数组、切片、字典等集合类型:

package main

import "fmt"

func main() {
    arr := []int{1, 2, 3, 4, 5}

    for i, val := range arr {
        fmt.Printf("arr[%d] = %d\n", i, val)
    }
}

在这个示例中,我们使用for range语句遍历一个整数类型的数组,并输出每个元素的值和下标。由于数组有5个元素,因此程序会执行5次循环,每次输出一个元素的值和下标。 while 循环 Go语言没有单独的while关键字,但是可以使用for语句模拟while循环:

package main

import "fmt"

func main() {
    i := 0

    for i < 5 {
        fmt.Println("i is", i)
        i++
    }
}

在这个示例中,我们使用for语句实现了一个while循环,输出04的数字。由于循环条件i < 5成立,因此程序会一直执行循环体,直到i的值变为5时停止。 do...while 循环 Go语言也没有do...while循环,但是可以通过组合for语句和break语句来实现类似的功能:

package main

import "fmt"

func main() {
    i := 0

    for {
        fmt.Println("i is", i)

        if i == 4 {
            break
        }

        i++
    }
}

在这个示例中,我们使用了一个无限循环的for语句,并通过if语句和break关键字来控制循环的结束条件。由于i的值在循环体中不断递增,因此程序会输出04的数字,直到i的值变为5时停止循环。

2.2.5 switch

Go语言中的switch语句用于根据不同的条件执行不同的代码块。它的基本语法如下:

switch variable {
case value1:
    //当variable等于value1时执行的代码块
case value2:
    //当variable等于value2时执行的代码块
default:
    //当variable不等于任何一个值时执行的代码块
}

其中,可以根据需要添加多个case语句和一个default语句。当变量等于某个值时,会执行该值对应的代码块;如果没有匹配的值,则会执行default语句中的代码块。 除了变量,还可以在switch语句中使用表达式,例如:

switch {
case i < 0:
    fmt.Println("i is negative")
case i > 0:
    fmt.Println("i is positive")
default:
    fmt.Println("i is zero")
}

此时,会根据表达式的值来匹配相应的代码块。 需要注意的是,每个case语句后面不需要加break语句,因为Go语言会自动跳出switch语句,除非使用fallthrough语句强制执行下一个case语句。

2.2.6 数组

Go语言中的数组是一种固定大小、存储相同类型元素的容器,其基本语法如下:

var array [size]type

其中,size表示数组大小,type表示数组中存储的元素类型。例如:

var nums [5]int

这段代码定义了一个包含5个int类型元素的数组。数组中的元素可以通过索引访问,索引从0开始,例如:

nums[0] = 10
nums[1] = 20
nums[2] = 30
nums[3] = 40
nums[4] = 50

以上代码将数组中的每个元素赋值为10、20、30、40、50。 除了定义和初始化数组外,还可以使用range关键字遍历数组中的元素,例如:

for i, num := range nums {
    fmt.Printf("nums[%d] = %d\n", i, num)
}

这段代码会遍历数组中的每个元素,并输出每个元素的索引和值。 需要注意的是,Go语言中的数组是值类型,即在函数调用中传递数组时会进行复制,因此对副本的修改不会影响原数组。如果需要传递指向数组的指针,可以使用切片或指针类型。

2.2.7 切片

Go语言中的切片是一种动态数组,其基本语法如下:

var slice []type

其中,type表示切片中存储的元素类型。与数组不同的是,切片的长度可以动态改变,而且存储空间由Go语言自动管理。 切片可以通过数组、指针或切片自行创建,并且可以使用make函数进行初始化,例如:

nums := []int{1, 2, 3, 4, 5}
letters := make([]string, 3)

以上代码分别创建了包含1到5整数元素的整型切片和长度为3的空字符串切片。 可以使用append函数向切片中添加元素,例如:

nums = append(nums, 6, 7, 8)

这段代码会将元素6、7、8依次添加到nums切片的末尾。 除了添加元素外,还可以使用copy函数复制切片,例如:

newSlice := make([]int, len(nums))
copy(newSlice, nums)

以上代码会将nums切片的元素复制到newSlice切片中。 需要注意的是,切片是引用类型,在函数调用中传递切片时会共享底层数组,因此对切片的修改会影响原数组和其它切片。如果需要避免共享底层数组,可以使用copy函数复制切片。

2.2.8 map

Go语言中的map是一种无序的键值对集合,基本语法如下:

var mapName map[keyType]valueType

其中,keyType表示键类型,valueType表示值类型。例如:

var scores map[string]int

这段代码定义了一个空的字符串到整型的映射。 可以使用make函数初始化map,例如:

scores = make(map[string]int)

这段代码会创建一个空的字符串到整型的映射,并分配内存。 可以使用[key] = value语法向map中添加元素,例如:

scores["Tom"] = 90
scores["Jerry"] = 80

这段代码会向scores映射中添加两个元素,键分别为"Tom"和"Jerry",值分别为90和80。 可以使用range关键字遍历map中的元素,例如:

for key, value := range scores {
    fmt.Printf("%s -> %d\n", key, value)
}

这段代码会遍历scores映射中的每个键值对,并输出每个键和值。 除了添加元素外,还可以使用delete函数删除map中的元素,例如:

delete(scores, "Jerry")

这段代码会删除scores映射中键为"Jerry"的元素。 需要注意的是,对于不存在的键,直接访问会返回对应值类型的零值,而不会引发异常。

2.2.9 range

Go语言中的range关键字用于遍历数组、切片、map以及通道中的元素。它的基本语法如下:

for index, value := range collection {
    //循环体
}

其中,collection表示要遍历的数组、切片、map或通道,index表示当前元素在collection中的索引(如果可以计算),value表示当前元素的值。例如:

nums := []int{1, 2, 3, 4, 5}
for i, num := range nums {
    fmt.Printf("第%d个元素:%d\n", i, num)
}

这段代码会遍历nums切片中的每个元素,并输出元素的索引和值。 需要注意的是,如果只需要遍历值而不需要索引,则可以使用下划线占位符来省略索引变量,例如:

letters := []string{"a", "b", "c", "d", "e"}
for _, letter := range letters {
    fmt.Printf("%s ", letter)
}

这段代码会遍历letters切片中的每个元素,并输出元素的值。 除了数组和切片,还可以使用range关键字遍历map中的键值对,例如:

scores := map[string]int{"Tom": 90, "Jerry": 80}
for name, score := range scores {
    fmt.Printf("%s的成绩是%d分\n", name, score)
}

此时,name表示map中每个键的值,score表示对应的值。

2.2.10 函数

Go语言中的函数是一段完成特定任务的代码块,可以接收参数并返回结果。它的基本语法如下:

func function_name(parameter_list) (result_list) {
    //函数体
}

其中,function_name表示函数名,parameter_list表示形参列表,result_list表示返回值列表(可以省略),函数体包含函数执行时要执行的代码。 例如,定义一个函数用于计算两个整数的和:

func add(x int, y int) int {
    return x + y
}

这段代码定义了一个名为add的函数,接收两个int类型的参数x和y,并返回它们的和。 调用函数时,需要传递实参给形参,例如:

sum := add(3, 5)
fmt.Printf("3 + 5 = %d\n", sum)

这段代码会调用add函数,并将实参3和5传递给它。执行完毕后,将返回值赋给变量sum,并输出结果。 需要注意的是,如果函数有多个返回值,则需要用逗号隔开,例如:

func swap(x, y int) (int, int) {
    return y, x
}

a, b := swap(1, 2)
fmt.Printf("交换后a=%d,b=%d\n", a, b)

这段代码定义了一个名为swap的函数,用于交换两个int类型的参数,并返回交换后的值。调用函数后,将返回值分别赋值给变量a和b,然后输出结果。 此外,可以使用函数作为参数传递给其他函数,或者用匿名函数(闭包)来实现函数的动态定义。

2.2.11 指针

在Go语言中,指针是一种用于存储变量内存地址的类型。指针通常用于传递函数参数、访问数组和结构体等场景。指针的基本语法如下:

var ptr *type

其中,type表示变量的类型,ptr表示指向该类型的指针。例如:

var a int = 10
var ptr *int
ptr = &a

这段代码定义了一个名为a的int类型变量,然后定义了一个名为ptr的int类型指针,并将ptr指向a的内存地址。可以使用&运算符取得变量的地址。 此时,指针ptr的值为a的地址,可以通过*运算符来访问该地址中存储的值,例如:

fmt.Printf("a的值为:%d\n", *ptr)

这段代码会输出a的值。 需要注意的是,如果指针没有被初始化,则它的值为nil,也就是空指针。在访问空指针的值时,会引发运行时异常。因此,在使用指针前,需要确保它已经被正确初始化。 指针类型也支持相等和不相等的比较操作。当两个指针指向同一个内存地址时,它们相等,否则不相等。具体用法可以参考以下示例:

x := 1
y := 2
var px *int = &x
var py *int = &y

fmt.Println(px == py)  // false
py = px
fmt.Println(px == py)  // true

2.2.12 结构体

在Go语言中,结构体是一种自定义的数据类型,代表了一组相关的属性和方法。结构体可以包含多个字段,每个字段可以是不同的类型。 结构体的基本语法如下:

type struct_name struct {
    field_name1 type1
    field_name2 type2
    ...
}

其中,struct_name表示结构体的名称,field_name表示字段名,type表示字段的类型。 例如,定义一个表示矩形的结构体:

type Rectangle struct {
    width  float64
    height float64
}

其中,width和height是矩形的宽度和高度,均为float64类型。 创建结构体实例时,需要使用new()或直接使用{}进行初始化,例如:

rect1 := new(Rectangle)
rect2 := &Rectangle{3.0, 4.0}

这段代码创建了两个矩形对象,分别为rect1和rect2。其中,rect1使用了new()函数来创建,rect2则使用了结构体字面量{}进行初始化。两种方法都可以有效地创建结构体实例。 在访问结构体成员时,可以使用"."符号,例如:

fmt.Printf("矩形1的宽度为%f,高度为%f\n", rect1.width, rect1.height)
fmt.Printf("矩形2的宽度为%f,高度为%f\n", rect2.width, rect2.height)

这段代码分别输出了两个矩形的具体大小。

2.2.13 结构体方法

结构体还支持方法,可以使用函数的方式进行定义。例如,为矩形增加一个计算面积的方法:

func (r *Rectangle) area() float64 {
    return r.width * r.height
}

fmt.Printf("矩形1的面积为%f\n", rect1.area())
fmt.Printf("矩形2的面积为%f\n", rect2.area())

这段代码分别输出了两个矩形的面积,其中area()方法是通过指针接收器定义的,可以直接在结构体对象上调用。

2.2.14 错误处理

在Go语言中,错误处理是一种常见的程序设计方式。Go语言中的错误通常用错误接口类型(error interface)表示。这个接口只包含一个方法:

type error interface {
    Error() string
}

如果函数返回一个非空的error接口,则说明函数出现了错误。在函数中通常使用errors.New()或fmt.Errorf()函数来创建一个新的error对象,例如:

func divide(x, y float64) (float64, error) {
    if y == 0 {
        return 0, errors.New("除数不能为0")
    }
    return x / y, nil
}

这段代码定义了一个计算除法的函数divide(),如果除数为0,则函数返回一个包含错误信息的error对象。否则返回计算结果和nil值。 在调用函数时,可以使用if语句判断是否出现了错误,例如:

result, err := divide(6.0, 2.0)
if err != nil {
    fmt.Println("计算错误:", err)
} else {
    fmt.Println("计算结果:", result)
}

这段代码通过divide()函数计算6.0除以2.0的结果,并判断是否出现了错误。如果出现了错误,则输出错误信息;否则输出计算结果。 除此之外,Go语言还提供了一种推荐的错误处理方式:defer-panic-recover机制。这种方式可以将错误处理逻辑集中到函数最后,使得代码更加简洁和易于维护。示例如下:

func foo() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("捕获到了一个错误:", err)
        }
    }()
    panic("发生了一个错误")
}

foo()

这段代码定义了一个函数foo(),在函数内部使用panic()函数引发了一个错误。同时,在函数的开头使用了defer来指定一个延迟函数,在这个函数中使用recover()函数来恢复程序执行。由于函数foo()发生了错误,会触发defer中的函数接管程序的执行,并输出错误信息。 需要注意的是,defer-panic-recover机制虽然便于使用,但并不适用于所有场景,并且容易被滥用。如果可以使用普通的返回值和error机制处理错误,则应该尽量避免使用panic和recover函数。

2.2.15 字符串操作

Go语言中字符串是一种基本数据类型,通常用于表示文本内容。在Go语言中,字符串使用双引号或反引号括起来,例如:

str1 := "hello, world"
str2 := `这是一段
多行
字符串`

其中,str1是一个普通的字符串,str2是一个包含多行内容的字符串,使用反引号进行括起来。 Go语言中的字符串支持多种常见操作,例如字符串连接、截取、替换等,常见的操作如下:

1.字符串连接:

str3 := str1 + " " + str2

这段代码将两个字符串连接起来,并赋值给str3变量。

2.字符串长度:

length := len(str1)

这段代码返回str1字符串的长度。

3.字符串截取:

substr := str1[0:5]

这段代码返回str1字符串中前5个字符组成的子串。

4.字符串替换:

newStr := strings.Replace(str1, "hello", "hi", -1)

这段代码将str1字符串中所有的"hello"替换成"hi"。 除此之外,Go语言中还有许多其他字符串操作函数,例如strings.Split()用于分割字符串,strings.ToLower()用于将字符串转换为小写等。在实际编程中,需要根据具体的需求选择合适的字符串操作函数。 需要注意的是,在Go语言中字符串是一种不可变的类型。如果需要修改字符串,通常需要使用[]byte类型来进行操作,例如:

byteStr := []byte(str1)
byteStr[0] = 'H'
str1 = string(byteStr)

这段代码首先将字符串转换为[]byte类型,然后修改第一个字符,最后再将[]byte转换回string类型。注意,在进行此类操作时应该多加小心,避免对字符串的长度和内容产生意外影响。

2.2.16 字符串格式化

Go语言中字符串格式化是一种将变量或表达式转换为字符串的常见操作,通常用于输出日志、调试信息和用户界面等场景。在Go语言中,字符串格式化使用fmt包中的Printf()函数实现,其基本语法如下:

func Printf(format string, args ...interface{}) (n int, err error)

其中,format参数是一个字符串,包含零个或多个占位符;args参数是一个不定长的interface类型切片,包含要替换占位符的值。 下面是几个常见的占位符及对应的格式化输出:

  • %v:以默认格式打印变量的值。
  • %T:打印变量的类型。
  • %t:打印布尔型变量的值。
  • %d:打印十进制整数。
  • %x:打印十六进制整数。
  • %f:打印浮点数。
  • %s:打印字符串。
  • %p:打印指针地址。
  • %%:打印百分号。 例如,下面的代码演示了如何使用Printf()函数进行字符串格式化输出:
name := "Alice"
age := 20
fmt.Printf("My name is %s, and I'm %d years old.\n", name, age)

这段代码中,%s和%d是两个占位符,它们分别代表要输出的字符串和整数的值。在Printf()函数中,使用name和age变量来替换占位符,输出格式化后的字符串。输出结果为:"My name is Alice, and I'm 20 years old."。 除了Printf()函数,还有许多其他的格式化函数,例如Sprintf()函数用于将格式化结果保存到一个字符串中,而Fprintf()函数可以将格式化结果输出到一个文件或IO流中。在实际编程中,需要根据具体需求选择合适的格式化函数。

2.2.17 JSON 处理

Go语言中,处理JSON数据十分方便。Go语言内置的encoding/json包提供了解析、生成和转换JSON数据的功能。 将Go语言中的数据编码为JSON格式,可以使用encoding/json包中的Marshal()函数进行处理。示例代码如下:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    p := Person{"Bob", 30}
    jsonByte, _ := json.Marshal(p)
    fmt.Println(string(jsonByte)) // 输出: {"name":"Bob","age":30}
}

在上面的代码中,定义了一个结构体Person,并使用Marshal()函数将结构体编码为JSON格式数据,在最后使用fmt.Println()函数将JSON字符串输出到控制台。需要注意的是,通常需要使用错误处理机制,以避免程序出现错误。在这里我们简单处理了错误。 如果需要将JSON格式数据解析为Go语言中的数据类型,则可以使用encoding/json包中的Unmarshal()函数。示例代码如下:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    jsonString := `{"name":"Bob","age":30}`
    var p Person
    if err := json.Unmarshal([]byte(jsonString), &p); err != nil {
        fmt.Println("json unmarshal failed")
        return
    }
    fmt.Println(p.Name, p.Age) // 输出: Bob 30
}

在上面的代码中,使用Unmarshal()函数将JSON格式数据解析为结构体Person,并将解析结果赋值给变量p。在最后使用fmt.Println()函数输出解析结果。需要注意的是,在解析过程中也需要进行错误处理。 除了基本的JSON处理函数外,encoding/json包还提供了许多其他的函数和类型,例如json.Decoder和json.Encoder等。在实际编程中,应根据具体需求选择合适的函数和类型实现JSON数据的处理。

2.2.18 时间处理

时间处理是计算机编程中非常常见的操作,Go语言内置了time包用于日期和时间相关的操作。本文将介绍Go语言中时间处理的基本语法和使用方法。

1.获取当前时间

要获取当前时间,可以使用time.Now()函数。示例代码如下:

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println("当前时间为:", now)
}

运行以上代码,输出的结果类似:当前时间为: 2022-08-12 11:22:33.964767 +0800 CST

2.时间格式化

将时间按照指定格式进行输出,可以使用time.Format()函数。其中,需要传入一个描述时间格式的字符串作为参数。示例代码如下:

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println(now.Format("2006-01-02 15:04:05"))
}

在上述示例代码中,我们使用2006-01-02 15:04:05作为时间格式化字符串,这是由Go语言的诞生时间决定的,所以在使用时间格式化字符串时需要严格遵守规范。

3.时间加减

Go语言中的时间类型是time.Time,它支持加减运算。可以使用time.Add()函数对时间进行加减操作,也可以使用time.AddDate()函数对年月日进行加减操作。示例代码如下:

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println("当前时间为:", now)

    // 将时间加上10分钟
    later := now.Add(time.Minute * 10)
    fmt.Println("10分钟后的时间为:", later)

    // 将时间减去2小时
    earlier := now.Add(- time.Hour * 2)
    fmt.Println("2小时前的时间为:", earlier)

    // 将年份加上1,月份减去2,天数加上3
    newTime := now.AddDate(1, -2, 3)
    fmt.Println("操作后的时间为:", newTime.Format("2006-01-02 15:04:05"))
}

在示例代码中,使用Add()函数和AddDate()函数对时间进行加减操作。

4.时间常量

Go语言中,time包定义了许多时间相关的常量,例如:

  • time.Second:代表一秒钟;
  • time.Minute:代表一分钟;
  • time.Hour:代表一小时。 这些常量可以用于对时间进行加减操作。 5.时间戳转化 在时间处理中,经常需要对时间戳(Unix时间戳)进行转化。在Go语言中,可以使用time.Unix()函数将时间戳转化为time.Time类型的时间,也可以使用time.Time类型的时间的Unix()方法将time.Time类型的时间转化为时间戳。示例代码如下:
package main

import (
    "fmt"
    "time"
)

func main() {
    // 将时间戳转化为time.Time类型的时间
    timestamp := int64(1628741516)
    t := time.Unix(timestamp, 0)
    fmt.Println(t.Format("2006-01-02 15:04:05"))

    // 将time.Time类型的时间转化为时间戳
    now := time.Now()
    unixTimestamp := now.Unix()
    fmt.Println(unixTimestamp)
}

以上示例代码中,使用time.Unix()函数将时间戳转化为time.Time类型的时间,并使用time.Time.Format()方法格式化输出时间。同时,使用time.Time类型的Unix()方法将time.Time类型的时间转化为时间戳。 以上就是Go语言中时间处理的基本语法和使用方法。在实际编程中,可以根据具体需求使用time包提供的其他函数和常量进行更加灵活的时间处理。

2.2.19 数字解析

在Go语言中,可以使用strconv包提供的函数对数字进行解析。本文将介绍strconv包提供的几个常用函数及其基本语法和使用方法。

1.ParseInt()

ParseInt()函数将字符串解析为有符号的整数。其中,第一个参数是待解析的字符串,第二个参数是进制数(例如:2表示二进制,8表示八进制,10表示十进制,16表示十六进制),第三个参数是结果类型的位数,可以选择int8、int16、int32、int64中的一种。示例代码如下:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 解析十进制字符串为整数
    i1, _ := strconv.ParseInt("123", 10, 64)
    fmt.Println(i1)

    // 解析二进制字符串为整数
    i2, _ := strconv.ParseInt("1010", 2, 64)
    fmt.Println(i2)
}

在以上示例代码中,我们使用ParseInt()函数将十进制字符串和二进制字符串分别解析为整数,并将结果打印输出。

2.ParseFloat()

ParseFloat()函数将字符串解析为浮点数。其中,第一个参数是待解析的字符串,第二个参数是结果类型的位数,可以选择float32或float64中的一种。示例代码如下:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 解析浮点数字符串
    f1, _ := strconv.ParseFloat("3.1415926", 64)
    fmt.Println(f1)
}

在以上示例代码中,我们使用ParseFloat()函数将浮点数字符串解析为浮点数,并将结果打印输出。

3.Atoi()

Atoi()函数将字符串解析为整数,并返回解析后的整数值。该函数等价于ParseInt(s, 10, 0),其中s表示待解析的字符串。示例代码如下:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 将字符串解析为整数
    i, _ := strconv.Atoi("123")
    fmt.Println(i)
}

在以上示例代码中,我们使用Atoi()函数将字符串解析为整数,并将结果打印输出。 总结一下: Go语言提供的strconv包中,ParseInt()函数可以将字符串解析为整数,ParseFloat()函数可以将字符串解析为浮点数,而Atoi()函数则是将字符串解析为整数的简便方式。在实际开发中,可以根据具体需求选择合适的函数进行数字解析。

2.2.20 进程信息

Go语言提供了os和os/exec两个包,可以用于操作系统级别的操作。其中,os包提供了获取进程信息的函数,本文将介绍os包提供的几个常用函数及其基本语法和使用方法。

1.Getpid()

Getpid()函数返回当前进程的进程ID。示例代码如下:

package main

import (
    "fmt"
    "os"
)

func main() {
    pid := os.Getpid()
    fmt.Println("当前进程的进程ID为:", pid)
}

在以上示例代码中,我们使用Getpid()函数获取当前进程的进程ID,并将结果打印输出。

2.Getppid()

Getppid()函数返回当前进程的父进程的进程ID。示例代码如下:

package main

import (
    "fmt"
    "os"
)

func main() {
    ppid := os.Getppid()
    fmt.Println("当前进程的父进程ID为:", ppid)
}

在以上示例代码中,我们使用Getppid()函数获取当前进程的父进程的进程ID,并将结果打印输出。

3.Getenv()

Getenv()函数获取指定环境变量的值。其中,需要传入一个字符串作为参数,表示要获取的环境变量的名称。示例代码如下:

package main

import (
    "fmt"
    "os"
)

func main() {
    path := os.Getenv("PATH")
    fmt.Println("环境变量PATH的值为:", path)
}

在以上示例代码中,我们使用Getenv()函数获取环境变量PATH的值,并将结果打印输出。

4.Stat()

Stat()函数返回指定文件的信息。其中,需要传入一个字符串作为参数,表示要获取信息的文件的路径。示例代码如下:

package main

import (
    "fmt"
    "os"
)

func main() {
    fileInfo, _ := os.Stat("/etc/passwd")
    fmt.Println("文件名称:", fileInfo.Name())
    fmt.Println("文件大小:", fileInfo.Size())
    fmt.Println("文件权限:", fileInfo.Mode().String())
    fmt.Println("修改时间:", fileInfo.ModTime())
}

在以上示例代码中,我们使用Stat()函数获取/etc/passwd文件的信息,并将文件名称、文件大小、文件权限和修改时间等信息打印输出。 总结一下: os包提供了获取进程信息的函数,包括获取当前进程的进程ID、父进程的进程ID,以及获取指定环境变量的值和指定文件的信息等。在实际开发中,可以根据具体需求选择合适的函数进行操作系统级别的操作。