[ Go语言-基础语言入门 | 青训营笔记 ]

116 阅读9分钟

1. 介绍

  • 欢迎来到Go语言的世界!作为一门新兴的编程语言,Go语言具有高效、简洁、安全等特点,逐渐受到了越来越多开发者的关注和喜爱。
  • 在本文中,我们将一起学习了解Go语言的基础语法。

2. 基础语法

2.1 写一个Hello World

让我们用最简单的方式先进入Go语言的世界——写一个Hello World。

package main

import "fmt"

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

其中,Keyword package 声明所在模块名称,Keyword import 引入必要的包,func main 是程序的入口函数,通过fmt包中的Println函数,输出"Hello World!" 的字符串信息。

2.2 变量的声明和定义

Go语言是静态类型语言,使用 var 关键字进行变量声明时需要指定数据类型。同时也可以使用下面这种简化的方式:

var message string = "Hello World!"
var a, b, c int = 1, 2, 3
s := "Go语言入门"

在第三行代码中,使用 := 代替了 var关键字和数据类型定义操作。这是因为 Go 语言的编译器能够通过变量字面值自动判断出变量的类型。

注意,在Go语言中,已声明但未使用的变量会引发编译错误。

2.3 if-else

在Go语言中,if 和 else 的语法与其他语言差不多。if 后跟条件表达式,然后是代码块。else 被用来指定与条件不匹配时执行的代码块。

if age >= 18 {
    fmt.Println("成年人")
} else {
    fmt.Println("未成年人")
}

2.4 for循环

Go 语言中成对出现的大括号 { } 必须与语句在同一行上。Go 语言中没有 while 循环,在循环语句中使用 for ,可以有单一的条件表达式,也可以有三个表达式组成的条件表达式。

for i := 0; i < 10; i++ {
   fmt.Printf("%d ", i)
}

其中,i := 0 是初始化语句,它定义并初始化了一个变量 i;i < 10 是条件表达式,它会在每次循环开始时测试条件 true or false 是否满足;i++ 是后置语句。每次循环结束后都会执行一次后置语句。

2.5 switch

在 Go 语言中,switch 语句类似于 if 语句,但是适用于多个条件判断场景。

switch grade {
case "A":
    fmt.Println("优秀")
case "B":
    fmt.Println("良好")
case "C":
    fmt.Println("及格")
default:
    fmt.Println("不及格")
}

2.6 数组

数组是指一组固定长度且类型相同的元素排列所组成的数据结构。在Go语言中,数组通过 [n]T 定义,其中 n 表示数组的长度,T 表示数组元素的类型。

var a [5]int 
a[2] = 3 
fmt.Println(a)

2.7 切片

切片(slice)是一种动态数组,在很多方面比传统的数组更灵活、更强大;同时也支持类似于数组的索引和遍历操作。

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

2.8 map

map 是一种键值对(key-value)数据结构,在需要快速查找特定键值时极其实用,和其它语言中的字典(dictionary)、哈希表(hash)、关联数组等类似。

ages := make(map[string]int)
ages["Alice"] = 31
ages["Bob"] = 20
ages["Charlie"] = 25
fmt.Println(ages["Bob"])

2.9 range

range 关键字用来实现for循环中针对数组、切片、字符串等的迭代操作。配合 for 循环可以形成迭代器遍历循环。

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
    fmt.Printf("2**%d = %d\n", i, v)
}

2.10 函数

Go语言的函数定义格式如下:

func functionName(parameter1 type, parameter2 type) returnType {
    // function body
}

其中,functionName 指定函数名,可以包含一个或多个输入参数和一个返回值类型。函数体内的逻辑是需要执行的操作。

2.11 指针

指针是一种特殊的变量,用于存储另一个变量的内存地址。Go语言的指针类型使用*来表示,通过&运算符获取一个变量的内存地址。对于指针类型变量,可以使用*运算符来获取其指向的变量的值。

// 定义指针变量
var a int = 10
var p *int = &a

// 获取指针指向的变量的值
fmt.Println(*p)   // 输出为 10

// 修改指针指向的变量的值
*p = 20
fmt.Println(a)    // 输出为 20

需要注意的是,Go语言中没有指针运算和指针比较等操作,以确保程序的安全性。

在实际编程过程中,指针通常用于传递函数参数、动态内存分配等场景。

2.12 结构体

结构体是一种复合类型,可以将多个不同类型的数据组合成一个有意义的整体。使用typestruct关键字进行定义,其中可包含不同类型的字段,每个字段都有自己的名称和类型。

// 定义一个结构体类型
type person struct {
    name string
    age int
    gender string
}

// 创建一个结构体实例
p := person{"Alice", 18, "female"}

// 访问结构体成员
fmt.Println(p.name)     // 输出为 Alice

可以使用.(点)来访问结构体中的字段。

2.13 结构体方法

与其他面向对象编程语言类似,Go语言也支持在结构体类型上定义方法。方法是与特定类型相关联的函数,使用func关键字和接收者(receiver)进行定义,而接收者就是该方法作用的结构体实例。

// 在 person 类型上定义方法
func (p *person) sayHello() {
    fmt.Printf("Hi, my name is %s, I'm %d years old.\n", p.name, p.age)
}

// 调用结构体方法
p.sayHello()    // 输出为 "Hi, my name is Alice, I'm 18 years old."

需要注意的是,方法接收者必须是指针类型或者值类型。

2.14 错误处理

Go语言中的错误处理非常灵活,通过返回一个error类型的值来表示某个操作是否出错。如果没有出错,则返回nil。可以使用if-else语句或者panic/recover机制来捕获和处理异常情况。

// 自定义错误类型
type MyError struct {
    code int
    message string
}

func (err MyError) Error() string {
    return fmt.Sprintf("error code: %d, message: %s", err.code, err.message)
}

// 使用自定义错误类型进行错误处理
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, MyError{1001, "division by zero"}
    }
    return a / b, nil
}

result, err := divide(10, 0)
if err != nil {
    fmt.Println(err)
} else {
    fmt.Println(result)
}

2.15 字符串操作

Go语言的字符串是不可变的,所以每个字符串都应被视为只读操作方式,任何修改字符串数据的尝试都将导致编译时错误。

要完成字符串拼接,在Go中可以使用+运算符或strings.Join()方法。

// 字符串拼接
str1 := "hello"
str2 := "world"
str3 := str1 + " " + str2
// 或者
strList := []string{"hello", "world"}
str4 := strings.Join(strList, " ")

截取字符串可以使用切片操作。需要注意的是,子串左边界从0开始,右边界从1开始,都包含在了结果字符串内。

// 截取字符串
str := "hello world"
substr := str[0:5] // "hello"

对于其他常见的字符串处理需求,Go语言也提供了相应的函数,例如:

// 替换字符串中的某个子串
newStr := strings.Replace(oldStr, oldSubstr, newSubstr, -1) // -1表示全部替换

// 大小写转换
upperStr := strings.ToUpper(str)
lowerStr := strings.ToLower(str)

// 判断字符串是否以某个前缀或后缀开头或结尾
hasPrefix := strings.HasPrefix(str, prefix)
hasSuffix := strings.HasSuffix(str, suffix)

// 分割字符串
subStrList := strings.Split(str, sep)

2.16 字符串格式化

Go语言的fmt包提供了非常灵活的字符串格式化功能。其中最常用的方式便是Printf()函数,可以打印各种格式标识符代表的值(例如:%d表示整数,%f表示浮点数,%s表示字符串)。

// 字符串格式化并输出到标准输出
fmt.Printf("str1: %s, str2: %s\n", str1, str2)

// 将格式化字符串输出成字符串
formattedStr := fmt.Sprintf("name: %s, age: %d", name, age)

2.17 JSON处理

Go语言内置了对JSON格式的支持,可以通过encoding/json包实现JSON格式数据和Go语言结构体之间的相互转化。

在将Go语言中的变量转化为JSON格式时,需要使用json.Marshal()函数。反过来,JSON数据可以转换为Go语言结构体类型,截止当前日期,也可以使用json.Unmarshal()函数。

例如,下面的代码演示了如何将一个结构体转换为JSON字符串,并且将这个字符串解析为一个新的结构体:

import (
    "encoding/json"
    "fmt"
)

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

func main() {
    p1 := Person{
        Name:   "Alice",
        Age:    30,
        Height: 170.5,
    }

    // 将结构体转为JSON字符串
    jsonData, err := json.Marshal(p1)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("JSON data:", string(jsonData))

    // 将JSON字符串解析为结构体
    var p2 Person
    if err := json.Unmarshal(jsonData, &p2); err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%+v\n", p2)
}

2.18 时间处理

Go语言的time包提供了各种用于时间处理和格式化的函数,使用这些函数可以获取当前时间、计算时间间隔等。

// 获取当前时间
now := time.Now()

// 时间转换成字符串
fmt.Println(now.Format("2006-01-02 15:04:05"))

// 字符串转换成时间
t, err := time.Parse("2006-01-02 15:04:05", "2023-05-12 21:27:00")
if err != nil {
    fmt.Println(err)
    return
}

// 计算两个时间间隔
duration := now.Sub(t)
fmt.Println(duration.Hours()) // 输出相差小时数

2.19 数字解析

Go语言提供了很多强大的数字解析功能,strconv包实现了基础类型和其它数据类型之间的相互转化,例如将字符串解析成整型、浮点型等。

import (
    "fmt"
    "strconv"
)

func main() {
    str := "100"
    
    // 将字符串转为int类型
    i, err := strconv.Atoi(str)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%d\n", i)
    
    // 将字符串转为float64类型
    f, err := strconv.ParseFloat(str, 64)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%f\n", f)
}

2.20 进程信息

Go语言的os包提供了访问进程相关信息的函数。可以获取进程ID,获取命令行参数、环境变量等信息。

下面的示例代码展示如何使用os包输出运行程序时传入的所有命令行参数:

import (
    "fmt"
    "os"
)

func main() {
    args := os.Args[1:]
    for _, arg := range args {
        fmt.Println(arg)
    }
}

3. 总结

  • 总的来说,虽然Go语言在语法上与其他编程语言有所不同,但是通过使用它独特的类型系统、并发机制、内存管理和错误处理等特性,可以编写出更加安全、高效的程序,适合用于分布式系统、网络服务和大规模数据处理等领域。
  • 呼~ 码字不易,对你有用的话可以点赞和收藏。