第2课:Golang基础语法

59 阅读6分钟

课程目标

  • 掌握Golang的基本语法,包括变量、常量、数据类型和运算符;
  • 理解Golang的控制结构,包括条件语句和循环语句;
  • 通过编写简单的程序,巩固对基础语法的理解。

1. 变量与常量

1.1 变量

变量是程序中用于存储数据的容器。在Golang中,变量需要显式声明类型,但也可以通过类型推断自动确定类型。

变量的声明

  • 使用var关键字声明变量:

    var name string
    name = "Golang"
    
  • 声明并初始化变量:

    var age int = 25
    
  • 使用类型推断:

    var score = 95.5 // 自动推断为float64类型
    
  • 简短声明(只能在函数内部使用):

    isActive := true
    

多变量声明

  • 同时声明多个变量:

    var x, y int = 10, 20
    
  • 使用简短声明:

    a, b := 1, "hello"
    

变量的零值

  • 如果变量声明时未初始化,Golang会为其赋予零值:

    • 数值类型:0
    • 字符串类型:""
    • 布尔类型:false

1.2 常量

常量是程序运行期间不可改变的值。使用const关键字声明常量。

常量的声明

  • 声明单个常量:

    const pi = 3.14159
    
  • 声明多个常量:

    const (
        e = 2.71828
        g = 9.81
    )
    

常量的类型

  • 常量可以是数值、字符串或布尔值:

    const name = "Golang"
    const isActive = true
    

2. 数据类型

Golang是一种静态类型语言,每个变量都有明确的类型。以下是Golang中的基本数据类型:

2.1 数值类型

  • 整数类型

    • int:根据平台可能是32位或64位;
    • int8int16int32int64:指定长度的有符号整数;
    • uint8uint16uint32uint64:指定长度的无符号整数。
  • 浮点数类型

    • float32:32位浮点数;
    • float64:64位浮点数(默认类型)。
  • 复数类型

    • complex64:由两个float32组成的复数;
    • complex128:由两个float64组成的复数。

2.2 字符串类型

  • 字符串是由字节组成的不可变序列,使用双引号或反引号表示:

    var name string = "Golang"
    var desc string = `Go is a programming language.`
    

2.3 布尔类型

  • 布尔类型只有两个值:truefalse

    var isActive bool = true
    

2.4. 数组(Array)

数组是一种固定长度的序列,用于存储相同类型的元素。数组的长度在声明时确定,且不可更改。

2.4.1 数组的声明与初始化

  • 声明一个长度为5的整数数组:

    var nums [5]int
    
  • 初始化数组:

    var nums = [5]int{1, 2, 3, 4, 5}
    
  • 使用...自动推断数组长度:

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

2.4.2 访问数组元素

  • 通过索引访问数组元素:

    fmt.Println(nums[0]) // 输出:1
    
  • 修改数组元素:

    nums[0] = 10
    fmt.Println(nums) // 输出:[10 2 3 4 5]
    

2.4.3 遍历数组

  • 使用for循环遍历数组:

    for i := 0; i < len(nums); i++ {
        fmt.Println(nums[i])
    }
    
  • 使用range遍历数组:

    for index, value := range nums {
        fmt.Println(index, value)
    }
    

2.5 切片(Slice)

切片是对数组的抽象,提供了更灵活的动态序列操作。切片的长度是可变的,底层仍然是一个数组。

2.5.1 切片的声明与初始化

  • 声明一个切片:

    var nums []int
    
  • 使用make函数创建切片:

    nums := make([]int, 5) // 长度为5,容量为5
    
  • 初始化切片:

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

2.5.2 切片的操作

  • 添加元素:

    nums = append(nums, 6)
    fmt.Println(nums) // 输出:[1 2 3 4 5 6]
    
  • 截取切片:

    subSlice := nums[1:3] // 截取索引1到2的元素
    fmt.Println(subSlice) // 输出:[2 3]
    
  • 修改切片元素:

    nums[0] = 10
    fmt.Println(nums) // 输出:[10 2 3 4 5 6]
    

2.5.3 切片的遍历

  • 使用for循环遍历切片:

    for i := 0; i < len(nums); i++ {
        fmt.Println(nums[i])
    }
    
  • 使用range遍历切片:

    for index, value := range nums {
        fmt.Println(index, value)
    }
    

2.6. 映射(Map)

映射是一种键值对集合,键和值可以是任意类型。映射是无序的,且键必须唯一。

2.6.1 映射的声明与初始化

  • 声明一个映射:

    var userMap map[string]int
    
  • 使用make函数创建映射:

    userMap := make(map[string]int)
    
  • 初始化映射:

    userMap := map[string]int{
        "Alice": 25,
        "Bob":   30,
    }
    

2.6.2 映射的操作

  • 添加或修改元素:

    userMap["Charlie"] = 28
    fmt.Println(userMap) // 输出:map[Alice:25 Bob:30 Charlie:28]
    
  • 删除元素:

    delete(userMap, "Bob")
    fmt.Println(userMap) // 输出:map[Alice:25 Charlie:28]
    
  • 查找元素:

    age, exists := userMap["Alice"]
    if exists {
        fmt.Println("Alice's age is", age)
    } else {
        fmt.Println("Alice not found")
    }
    

2.6.3 映射的遍历

  • 使用range遍历映射:

    for key, value := range userMap {
        fmt.Println(key, value)
    }
    

2.7. 结构体(Struct)

结构体是一种自定义的复合类型,用于将多个字段组合在一起。

2.7.1 结构体的声明与初始化

  • 声明一个结构体:

    type Person struct {
        Name string
        Age  int
    }
    
  • 初始化结构体:

    p := Person{Name: "Alice", Age: 25}
    fmt.Println(p) // 输出:{Alice 25}
    

2.7.2 访问结构体字段

  • 访问字段:

    fmt.Println(p.Name) // 输出:Alice
    
  • 修改字段:

    p.Age = 30
    fmt.Println(p) // 输出:{Alice 30}
    

2.7.3 结构体的嵌套

  • 嵌套结构体:

    type Address struct {
        City  string
        State string
    }
    
    type Employee struct {
        Name    string
        Age     int
        Address Address
    }
    
    emp := Employee{
        Name: "Bob",
        Age:  30,
        Address: Address{
            City:  "New York",
            State: "NY",
        },
    }
    fmt.Println(emp) // 输出:{Bob 30 {New York NY}}
    

2.8. 指针(Pointer)

指针是一种存储变量内存地址的类型,通过指针可以间接访问或修改变量的值。

2.8.1 指针的声明与初始化

  • 声明一个指针:

    var p *int
    
  • 获取变量的地址:

    num := 10
    p = &num
    fmt.Println(p) // 输出:0xc0000180a8(内存地址)
    

2.8.2 通过指针访问值

  • 使用``操作符访问指针指向的值:

    fmt.Println(*p) // 输出:10
    
  • 修改指针指向的值:

    *p = 20
    fmt.Println(num) // 输出:20
    

2.8.3 指针与结构体

  • 使用指针访问结构体字段:

    emp := Employee{Name: "Alice", Age: 25}
    p := &emp
    fmt.Println((*p).Name) // 输出:Alice
    fmt.Println(p.Name)    // 输出:Alice(语法糖)
    

3. 运算符

3.1 算术运算符

  • 加法:+
  • 减法:-``
  • 乘法:*``
  • 除法:/
  • 取余:%

3.2 比较运算符

  • 等于:==
  • 不等于:!=
  • 大于:>
  • 小于:<
  • 大于等于:>=
  • 小于等于:<=

3.3 逻辑运算符

  • 逻辑与:&&
  • 逻辑或:||
  • 逻辑非:!

3.4 赋值运算符

  • 简单赋值:=
  • 复合赋值:+===/=

3.5 位运算符

  • 按位与:&
  • 按位或:|
  • 按位异或:^
  • 左移:<<
  • 右移:>>

4. 控制结构

4.1 条件语句

  • if语句

    if age >= 18 {
        fmt.Println("You are an adult.")
    } else {
        fmt.Println("You are a minor.")
    }
    
  • if-else if-else语句

    if score >= 90 {
        fmt.Println("Grade: A")
    } else if score >= 80 {
        fmt.Println("Grade: B")
    } else {
        fmt.Println("Grade: C")
    }
    
  • switch语句

    switch day {
    case "Monday":
        fmt.Println("Today is Monday.")
    case "Tuesday":
        fmt.Println("Today is Tuesday.")
    default:
        fmt.Println("Today is another day.")
    }
    

4.2 循环语句

  • for循环

    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }
    
  • while循环(使用for实现):

    i := 0
    for i < 5 {
        fmt.Println(i)
        i++
    }
    
  • 无限循环

    for {
        fmt.Println("This loop will run forever.")
    }
    
  • range循环(用于遍历数组、切片、映射等):

    nums := []int{1, 2, 3}
    for index, value := range nums {
        fmt.Println(index, value)
    }
    

5. 实战练习

5.1 编写一个简单的计算器

  • 要求:

    • 支持加、减、乘、除运算;
    • 用户输入两个数字和运算符,程序输出结果。
  • 示例代码:

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        var a, b float64
        var op string
    
        fmt.Print("Enter first number: ")
        fmt.Scan(&a)
    
        fmt.Print("Enter second number: ")
        fmt.Scan(&b)
    
        fmt.Print("Enter operator (+, -, *, /): ")
        fmt.Scan(&op)
    
        switch op {
        case "+":
            fmt.Printf("Result: %.2f\\n", a+b)
        case "-":
            fmt.Printf("Result: %.2f\\n", a-b)
        case "*":
            fmt.Printf("Result: %.2f\\n", a*b)
        case "/":
            if b == 0 {
                fmt.Println("Error: Division by zero.")
            } else {
                fmt.Printf("Result: %.2f\\n", a/b)
            }
        default:
            fmt.Println("Invalid operator.")
        }
    }
    

5.2 编写一个猜数字游戏

  • 要求:

    • 程序随机生成一个1到100的整数;
    • 用户输入猜测的数字,程序提示“大了”或“小了”,直到猜中为止。
  • 示例代码:

    package main
    
    import (
        "fmt"
        "math/rand"
        "time"
    )
    
    func main() {
        rand.Seed(time.Now().UnixNano())
        target := rand.Intn(100) + 1
        var guess int
    
        for {
            fmt.Print("Enter your guess (1-100): ")
            fmt.Scan(&guess)
    
            if guess < target {
                fmt.Println("Too small!")
            } else if guess > target {
                fmt.Println("Too big!")
            } else {
                fmt.Println("You got it!")
                break
            }
        }
    }
    

6. 总结

  • 本课介绍了Golang的基础语法,包括变量、常量、数据类型、运算符和控制结构;
  • 通过编写简单的程序,学员可以巩固对基础语法的理解;
  • 下一课将深入学习Golang的函数与包,为后续的接口测试打下坚实基础。