第一讲:Go语言开发入门:环境搭建与基础语法

发布于:2024-10-08 ⋅ 阅读:(8) ⋅ 点赞:(0)

环境搭建

windows环境搭建

参考之前博客:Go语言入门:从零开始的快速指南

Mac环境搭建

安装GO
使用 Homebrew 安装 Go

Homebrew 是 macOS 上常用的包管理工具,使用 Homebrew 安装 Go 非常简单。

  1. 打开终端(Terminal)。

  2. 确保你已经安装了 Homebrew。如果没有安装,可以使用以下命令进行安装:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
  3. 使用 Homebrew 安装 Go:

    brew install go
    

    安装完成后,Go 的执行文件和相关工具将会被安装到 /usr/local/bin/ 中,默认版本是最新稳定版。

手动下载安装 Go

如果你不使用 Homebrew,也可以手动从官网下载安装:

  1. 访问 Go 官方下载页面
  2. 下载适用于 macOS 的安装包(通常是 .pkg 文件)。
  3. 下载完成后,双击安装包并按照提示进行安装。

安装成功后,Go 会被安装到 /usr/local/go 目录。

配置环境变量

Go 的安装目录 /usr/local/go 包含了 Go 的所有工具和命令行工具。为了让系统知道 Go 的位置,我们需要配置 Go 的 GOPATHGOROOT 环境变量。

配置环境变量
  1. 打开终端,编辑你的 ~/.zshrc 文件(macOS 默认使用 Zsh,或者你使用的是 Bash 则编辑 ~/.bash_profile):

    nano ~/.zshrc
    
  2. 在文件末尾添加以下内容:

    # Go 环境变量配置
    export GOPATH=$HOME/go
    export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
    
    • GOPATH:这是 Go 的工作区目录,存储你的 Go 项目和依赖。默认建议使用 ~/go 目录。
    • PATH:将 Go 的二进制文件添加到 PATH 中,确保你可以在任何地方使用 Go 的命令。
  3. 保存文件并退出(按 Ctrl + O 保存,按 Ctrl + X 退出)。

  4. 运行以下命令使配置立即生效:

    source ~/.zshrc
    
检查 Go 是否正确安装

在终端输入以下命令来检查 Go 是否成功安装:

go version

如果安装成功,你会看到类似以下的输出:

go version go1.23.1 darwin/arm64
验证安装:编写第一个 Go 程序

接下来,我们编写一个简单的 Go 程序来验证安装是否成功。

创建 Go 工作区

首先,在 GOPATH 中创建一个 Go 项目的工作目录:

mkdir -p ~/go/src/hello
cd ~/go/src/hello
编写 Hello World 程序

在该目录下创建一个名为 main.go 的文件,并写入以下内容:

package main

import "fmt"

func main() {
    fmt.Println("Hello, Go!")
}
运行程序

在终端中运行以下命令来编译并执行这个 Go 程序:

go run main.go

你应该会看到以下输出:

Hello, Go!
编译程序

如果你希望将程序编译成可执行文件,可以使用 go build 命令:

go build

编译完成后,你会在当前目录下看到一个名为 hello(或者 hello.exe,如果你在 Windows 上运行)的可执行文件。你可以直接运行它:

./hello

你将再次看到 Hello, Go! 的输出。

常用的 Go 命令

以下是一些常用的 Go 命令,可以帮助你在开发中快速上手:

  • go run:直接运行 Go 源代码文件。
  • go build:编译源代码,生成可执行文件。
  • go install:编译并安装包和依赖。
  • go fmt:格式化 Go 源代码文件。
  • go test:运行单元测试。
  • go get:下载和安装远程包。
  • go doc:查看 Go 包的文档。

Go语言基础语法

1. 变量(Variables)

在 Go 中,变量通过 var 关键字声明。

package main

import "fmt"

func main() {
    // 声明一个整型变量
    var a int = 10

    // 声明一个字符串变量
    var str string = "Hello, Go!"

    // 使用类型推断(编译器会自动推断类型)
    var b = 20

    // 简短声明(只能在函数内使用)
    c := 30

    fmt.Println(a, str, b, c)
}

变量相关知识:

  • 使用 var 关键字可以声明变量。
  • 通过 := 进行简短声明,不需要 var 关键字,只能在函数内部使用。
  • Go 是静态类型语言,变量类型在编译时就确定,不能改变。

2. 常量(Constants)

常量通过 const 关键字声明,常量的值在编译时就确定,不能被修改。

package main

import "fmt"

func main() {
    const pi = 3.14159
    const str = "Hello, Go!"
    fmt.Println(pi, str)
}

常量相关知识:

  • 常量的值必须是编译时确定的,不能运行时赋值。
  • 常量可以是数值、字符串、布尔值等。

3. 计算符号(Operators)

Go 支持常见的算术运算符、关系运算符和逻辑运算符:

package main

import "fmt"

func main() {
    a, b := 10, 20

    // 算术运算符
    fmt.Println("加法: ", a+b)
    fmt.Println("减法: ", a-b)
    fmt.Println("乘法: ", a*b)
    fmt.Println("除法: ", a/b)
    fmt.Println("取模: ", a%b)

    // 关系运算符
    fmt.Println("相等: ", a == b)
    fmt.Println("不等: ", a != b)
    fmt.Println("大于: ", a > b)
    fmt.Println("小于: ", a < b)

    // 逻辑运算符
    fmt.Println("逻辑与: ", a > 5 && b > 15)
    fmt.Println("逻辑或: ", a > 15 || b > 15)
    fmt.Println("逻辑非: ", !(a > 15))
}

4. 字符串(Strings)

字符串是不可变的 Unicode 字符序列,可以通过 " 包含字符串,或者通过反引号 包含多行字符串。

package main

import "fmt"

func main() {
    var str1 string = "Hello"
    str2 := "World"

    // 多行字符串
    str3 := `这是
    多行
    字符串`
    
    // 字符串拼接
    combined := str1 + ", " + str2

    fmt.Println(combined)
    fmt.Println(str3)
}

字符串相关知识:

  • 使用 + 可以拼接字符串。
  • 使用反引号可以定义多行字符串。

5. 条件表达式(Condition Expressions)

Go 中的条件表达式使用 ifelse,条件表达式不需要用括号包裹。

package main

import "fmt"

func main() {
    a := 10

    if a > 5 {
        fmt.Println("a 大于 5")
    } else {
        fmt.Println("a 小于或等于 5")
    }

    // 带初始化的 if 语句
    if b := a * 2; b > 15 {
        fmt.Println("b 大于 15")
    } else {
        fmt.Println("b 小于或等于 15")
    }
}

6. 分支表达式(Switch Statements)

switch 语句是 Go 中多分支选择的常用方法。

package main

import "fmt"

func main() {
    a := 2

    switch a {
    case 1:
        fmt.Println("a 等于 1")
    case 2:
        fmt.Println("a 等于 2")
    default:
        fmt.Println("a 不等于 1 或 2")
    }
}

switch 的特点:

  • switch 不需要像其他语言中那样使用 break,每个 case 执行完毕后会自动结束。
  • 可以在 case 中进行条件匹配。

7. 循环(Loops)

Go 只有一种循环结构 for,没有 whiledo-while

package main

import "fmt"

func main() {
    // 基本的 for 循环
    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }

    // 类似 while 的 for 循环
    i := 0
    for i < 5 {
        fmt.Println(i)
        i++
    }

    // 无限循环
    // for {
    //     fmt.Println("无限循环")
    // }
}

8. 数组(Arrays)

数组是具有固定长度的同类型元素序列。

package main

import "fmt"

func main() {
    var arr [5]int // 定义一个长度为5的数组
    arr[0] = 1
    arr[1] = 2

    // 初始化时直接赋值
    arr2 := [3]int{1, 2, 3}

    fmt.Println(arr)
    fmt.Println(arr2)
}

数组相关知识:

  • 数组的长度是固定的,一旦声明,长度就不能改变。

9. 切片(Slices)

切片是基于数组的动态大小的序列,比数组更加灵活。

package main

import "fmt"

func main() {
    // 声明并初始化切片
    var slice []int = []int{1, 2, 3}

    // 使用 append 添加元素
    slice = append(slice, 4)

    // 通过切片创建切片
    newSlice := slice[1:3]

    fmt.Println(slice)
    fmt.Println(newSlice)
}

切片相关知识:

  • 切片是一种引用类型,指向底层数组。
  • 使用 append 函数可以动态地向切片添加元素。

10. Map(字典)

Map 是键值对的集合,可以通过键快速查找对应的值。

package main

import "fmt"

func main() {
    // 创建一个 map
    var myMap map[string]int = map[string]int{
        "Alice": 25,
        "Bob":   30,
    }

    // 添加元素
    myMap["Charlie"] = 35

    // 查找元素
    age := myMap["Alice"]

    // 判断键是否存在
    age, exists := myMap["David"]
    if exists {
        fmt.Println("David 的年龄是", age)
    } else {
        fmt.Println("David 不存在")
    }

    fmt.Println(myMap)
}

11. 简单函数(Functions)

Go 中的函数通过 func 关键字定义,可以返回多个值。

package main

import "fmt"

// 定义一个返回两个整数相加的函数
func add(a int, b int) int {
    return a + b
}

// 定义一个返回多个值的函数
func swap(a, b int) (int, int) {
    return b, a
}

func main() {
    result := add(3, 4)
    fmt.Println("3 + 4 =", result)

    x, y := swap(10, 20)
    fmt.Println("交换后:", x, y)
}

函数相关知识:

  • 函数可以有多个返回值。
  • 参数类型相同的参数可以合并写在一起,如 (a, b int)
  • 返回值类型写在函数名和参数列表之后。

两个小练习

练习 1:计算多个人的平均体脂

  • 实现完整的体脂计算器
  • 连续输入三人的姓名、性别、身高、体重、年龄信息
  • 计算每个人的 BMI、体脂率

输出:

  • 每个人姓名、BMI、体脂率、建议
  • 总人数、平均体脂率

运用到的知识:

  1. 变量和常量
    • 声明和使用变量来存储用户输入的身高、体重、年龄等信息。
    • 使用 := 进行简短声明,比如 a := 10
  2. 输入和输出
    • 使用 fmt.Scanln 来获取用户输入,并使用 fmt.Println 输出结果。
  3. 条件表达式
    • 使用 if 语句来判断体脂率的不同范围,并给出不同的健康建议。
  4. 循环
    • 使用 for 循环来处理多个人的输入和体脂计算。
  5. 函数
    • 编写了多个函数,如 calculateBMIcalculateBodyFatRategiveSuggestion,这些函数帮助简化代码结构并实现代码复用。
  6. 数组和切片
    • 使用了数组来存储每个人的信息,如身高、体重、年龄等。
    • 切片可以方便地处理可变大小的数据集合。
package main

import (
	"fmt"
)

func main() {
	// 定义数组来存储姓名、性别、身高、体重、年龄、BMI 和体脂率
	var names [3]string
	var genders [3]string
	var heights [3]float64
	var weights [3]float64
	var ages [3]int
	var BMIs [3]float64
	var bodyFatRates [3]float64

	// 输入三个人的信息
	for i := 0; i < 3; i++ {
		fmt.Printf("请输入第 %d 个人的信息:\n", i+1)
		fmt.Print("姓名: ")
		fmt.Scan(&names[i])
		fmt.Print("性别 (male/female): ")
		fmt.Scan(&genders[i])
		fmt.Print("身高 (米): ")
		fmt.Scan(&heights[i])
		fmt.Print("体重 (公斤): ")
		fmt.Scan(&weights[i])
		fmt.Print("年龄: ")
		fmt.Scan(&ages[i])

		// 计算 BMI
		BMIs[i] = calculateBMI(heights[i], weights[i])

		// 计算体脂率
		bodyFatRates[i] = calculateBodyFatRate(genders[i], BMIs[i], ages[i])
	}

	// 输出每个人的BMI、体脂率和建议
	for i := 0; i < 3; i++ {
		fmt.Printf("\n姓名: %s\n", names[i])
		fmt.Printf("BMI: %.2f\n", BMIs[i])
		fmt.Printf("体脂率: %.2f%%\n", bodyFatRates[i])
		fmt.Println(giveSuggestion(bodyFatRates[i], genders[i]))
	}

	// 计算并输出平均体脂率
	calculateAndPrintAverageBodyFatRate(bodyFatRates[:])
}

// 计算 BMI
func calculateBMI(height, weight float64) float64 {
	return weight / (height * height)
}

// 计算体脂率
func calculateBodyFatRate(gender string, BMI float64, age int) float64 {
	if gender == "male" {
		return (1.20 * BMI) + (0.23 * float64(age)) - 16.2
	}
	return (1.20 * BMI) + (0.23 * float64(age)) - 5.4
}

// 根据体脂率给出建议
func giveSuggestion(bodyFatRate float64, gender string) string {
	var suggestion string
	if gender == "male" {
		switch {
		case bodyFatRate < 10:
			suggestion = "建议:过瘦,适当增加体重。"
		case bodyFatRate >= 10 && bodyFatRate < 20:
			suggestion = "建议:体脂正常,保持良好状态。"
		case bodyFatRate >= 20 && bodyFatRate < 25:
			suggestion = "建议:体脂偏高,适当控制体重。"
		default:
			suggestion = "建议:肥胖,建议制定减脂计划。"
		}
	} else {
		switch {
		case bodyFatRate < 20:
			suggestion = "建议:过瘦,适当增加体重。"
		case bodyFatRate >= 20 && bodyFatRate < 30:
			suggestion = "建议:体脂正常,保持良好状态。"
		case bodyFatRate >= 30 && bodyFatRate < 35:
			suggestion = "建议:体脂偏高,适当控制体重。"
		default:
			suggestion = "建议:肥胖,建议制定减脂计划。"
		}
	}
	return suggestion
}

// 计算并输出平均体脂率
func calculateAndPrintAverageBodyFatRate(bodyFatRates []float64) {
	totalBodyFat := 0.0
	for _, bodyFatRate := range bodyFatRates {
		totalBodyFat += bodyFatRate
	}
	averageBodyFatRate := totalBodyFat / float64(len(bodyFatRates))
	fmt.Printf("\n总人数: %d\n", len(bodyFatRates))
	fmt.Printf("平均体脂率: %.2f%%\n", averageBodyFatRate)
}

说明:

  1. 数组存储

    • 使用 namesgendersheightsweightsagesBMIsbodyFatRates 这几个数组分别存储每个人的信息。
    • 每个数组的长度为3,适用于存储三个人的数据。
  2. 函数封装

    • calculateBMI:根据身高和体重计算 BMI。
    • calculateBodyFatRate:根据性别、BMI 和年龄计算体脂率。
    • giveSuggestion:根据体脂率给出建议。
    • calculateAndPrintAverageBodyFatRate:计算并输出平均体脂率。
  3. 示例输入/输出

请输入第 1 个人的信息:
姓名: 张三
性别 (male/female): male
身高 (米): 1.75
体重 (公斤): 70
年龄: 30

请输入第 2 个人的信息:
姓名: 李四
性别 (male/female): female
身高 (米): 1.65
体重 (公斤): 68
年龄: 28

请输入第 3 个人的信息:
姓名: 王五
性别 (male/female): male
身高 (米): 1.80
体重 (公斤): 85
年龄: 35

姓名: 张三
BMI: 22.86
体脂率: 19.55%
建议:体脂正常,保持良好状态。

姓名: 李四
BMI: 24.98
体脂率: 31.27%
建议:肥胖,建议制定减脂计划。

姓名: 王五
BMI: 26.23
体脂率: 24.80%
建议:体脂偏高,适当控制体重。

总人数: 3
平均体脂率: 25.87%

练习 2:判断两条线是否平行

编写一个程序来判断两条直线是否平行。你需要通过两点计算每条线的斜率,并比较两条线的斜率是否相等,来确定它们是否平行。

运用到的知识:

  1. 变量

    • 使用 var:= 声明变量,存储用户输入的点坐标。
  2. 输入和输出

    • 使用 fmt.Scanln 获取用户输入,并用 fmt.Println 输出结果。
  3. 条件表达式

    • 使用 if 语句来判断两条线是否垂直(即 x 坐标相同),如果两条线都垂直,它们就是平行的。
  4. 函数

    • 使用了函数 calculateSlope 来计算斜率,areLinesParallel 来判断两条线是否平行,这些函数让代码结构更加清晰。

通过比较两条线的斜率来判断它们是否平行。两点决定一条直线,斜率的公式为: 斜率 = y 2 − y 1 x 2 − x 1 \text{斜率} = \frac{y_2 - y_1}{x_2 - x_1} 斜率=x2x1y2y1。如果两条线的斜率相同,那么它们就是平行的。需要注意的是,当两点的 x 1 = = x 2 x_1 == x_2 x1==x2 时,斜率不存在(垂直线)。

package main

import (
	"fmt"
)

// 计算两点间的斜率
func calculateSlope(x1, y1, x2, y2 float64) (float64, bool) {
	// 如果两点的x坐标相同,斜率不存在,返回false表示斜率不存在(垂直线)
	if x1 == x2 {
		return 0, false
	}
	// 计算斜率
	slope := (y2 - y1) / (x2 - x1)
	return slope, true
}

// 判断两条直线是否平行
func areLinesParallel(x1, y1, x2, y2, x3, y3, x4, y4 float64) bool {
	// 计算两条线的斜率
	slope1, exists1 := calculateSlope(x1, y1, x2, y2)
	slope2, exists2 := calculateSlope(x3, y3, x4, y4)

	// 如果一条线是垂直线,而另一条不是,则不平行
	if !exists1 && !exists2 {
		return true // 两条线都垂直,平行
	} else if !exists1 || !exists2 {
		return false // 一条垂直,另一条不垂直,不平行
	}

	// 如果斜率相等,说明平行
	return slope1 == slope2
}

func main() {
	var x1, y1, x2, y2 float64
	var x3, y3, x4, y4 float64

	// 输入第一条线的两点坐标
	fmt.Println("请输入第一条直线的两个点坐标:")
	fmt.Print("点1 (x1, y1): ")
	fmt.Scan(&x1, &y1)
	fmt.Print("点2 (x2, y2): ")
	fmt.Scan(&x2, &y2)

	// 输入第二条线的两点坐标
	fmt.Println("请输入第二条直线的两个点坐标:")
	fmt.Print("点3 (x3, y3): ")
	fmt.Scan(&x3, &y3)
	fmt.Print("点4 (x4, y4): ")
	fmt.Scan(&x4, &y4)

	// 判断两条线是否平行
	if areLinesParallel(x1, y1, x2, y2, x3, y3, x4, y4) {
		fmt.Println("这两条线是平行的")
	} else {
		fmt.Println("这两条线不平行")
	}
}

说明:

  1. calculateSlope :计算给定两点间的斜率,如果两点的 x 坐标相同,返回 false 表示垂直线。
  2. areLinesParallel :比较两条线的斜率,判断它们是否平行。如果斜率相等,则平行;如果一条线垂直而另一条线不垂直,则不平行。

示例输入/输出:

请输入第一条直线的两个点坐标:
点1 (x1, y1): 1 1
点2 (x2, y2): 3 3
请输入第二条直线的两个点坐标:
点3 (x3, y3): 2 2
点4 (x4, y4): 4 4
这两条线是平行的