第05讲 实现Go的参数接收
本讲义根据视频实际讲解内容整理,涵盖命令行参数接收、OS包使用、变量声明、格式化输出、多返回值函数等核心知识点。
一、命令行参数概述
1.1 什么是命令行参数
在Java中,我们使用 args 来接收命令行参数:
public static void main(String[] args) {
// Java中的args
}
Go语言中同样需要接收命令行参数,但需要借助 OS包 来实现:
package main
import (
"os"
)
func main() {
// 通过 os.Args 接收命令行参数
}
1.2 OS包的特点
- OS 是 Go 语言的内置标准库,不需要手动安装
- 导入方式:使用
import "os" - 多个包导入时,使用括号包裹:
import (
"os"
"fmt"
)
二、OS.Args 详解
2.1 编译安全机制
在Go中,如果你导入了一个包但没有使用它,编译会报错:
import (
"os" // 如果没用到 os,编译报错!
"fmt"
)
老师强调:这是Go语言为了代码安全性和避免资源浪费而设计的机制——未使用的包和变量必须去掉,否则无法编译通过。
2.2 OS.Args 的返回值
os.Args 返回一个 string 类型的数组(切片):
// os.Args 的类型:[]string
args := os.Args
2.3 获取参数长度
使用 len() 函数计算数组长度:
length := len(os.Args)
三、变量声明与初始化
3.1 Go变量声明的特点
Go语言的变量类型在变量名的后面(与Java/C相反):
// Go 的写法(类型在后)
var str string
var i int
// Java 的写法(类型在前)
// String str;
// int i;
3.2 两种变量声明方式
方式一:传统 var 声明
var str string = "hello"
var i int = 0
方式二:短变量声明(:=)
str := "hello"
i := 0
3.3 不需要分号
Go语言中不需要写分号,保存时IDE会自动格式化并移除多余的分号:
// 写了分号也能编译,但保存后自动消失
var str string = "hello"; // 保存后 → var str string = "hello"
四、For循环与参数拼接
4.1 传统For循环
Go只有 for 关键字,没有 while,但 for 可以实现所有循环需求:
package main
import (
"os"
"fmt"
)
func main() {
var str string
var sep string = " "
// 传统 for 循环
for i := 0; i < len(os.Args); i++ {
str += os.Args[i] + sep
}
fmt.Println(str)
}
4.2 字符串拼接
使用 += 进行字符串拼接:
str += os.Args[i] + " "
4.3 格式化输出
Go 提供了三种打印函数,类似于 C 语言的 printf:
| 函数 | 说明 | 示例 |
|---|---|---|
fmt.Print() |
原样输出,不换行 | fmt.Print("hello") |
fmt.Println() |
输出后自动换行 | fmt.Println("hello") |
fmt.Printf() |
格式化输出 | fmt.Printf("你好,我是%s", "小明") |
格式化占位符:
fmt.Printf("%d", 100) // 整数
fmt.Printf("%s", "hello") // 字符串
fmt.Printf("%f", 3.14) // 浮点数
注意:
%d只能用于整数,不能放字符串,否则会出错。这与 C 语言的printf用法一致。
五、编译与运行
5.1 go build 编译
编译后生成可执行文件,可以带参数运行:
# 编译
go build
# 运行(带参数)
./demo param1 param2 param3
老师类比:这类似于 Docker 的用法——
docker run -itd --name mycontainer ubuntu /bin/bash,命令后面跟参数,程序根据参数执行不同逻辑。
5.2 实际应用场景
老师举了一个实际例子——启动 GoGhost 时带 web 参数:
# 带 web 参数启动 Web 服务
./goghost web
程序通过判断参数来决定启动哪种服务。这就是命令行参数的实际用途:程序启动时根据参数执行不同功能。
六、短变量声明(:=)的限制
6.1 := 不能在函数外使用
// ✅ 函数内可以使用 :=
func main() {
str := "hello" // 正确
}
// ❌ 函数外不能使用 :=
str := "hello" // 编译错误!
6.2 := 与多返回值
短变量声明 := 在函数返回多个值时特别有用:
// Go 的函数可以返回多个值(Java做不到)
func test() (string, int) {
return "hello", 100
}
func main() {
// 两个变量接收两个返回值
str, num := test()
fmt.Println(str, num)
}
重点:如果前面定义了两个变量,函数也必须返回两个值,一一对应,数量不匹配会报错。
七、OS包其他功能预览
OS 包不仅有 Args,还包含丰富的文件操作功能:
// 文件信息结构体
type FileInfo struct {
// ...
}
// 文件模式
type FileMode int
// 打开文件
func Open(name string) (*File, error)
// 读取文件内容
func ReadFile(name string) ([]byte, error)
7.1 error 返回值
Go 的文件操作函数通常会返回一个 error 类型的值:
data, err := os.ReadFile("test.txt")
if err != nil {
// 处理错误
}
老师说明:这类似于 Java 中的抛出异常,但 Go 不使用 try-catch,而是通过返回值来传递错误信息。
7.2 结构体概念预览
type File struct {
// 内部字段
}
老师提到:
type File struct定义了一个结构体,*File是指向结构体的指针,后续课程会详细讲解。
八、常见问题:多个 main 函数冲突
8.1 问题现象
如果一个目录下有两个 .go 文件都包含 func main(),编译会报错:
// test1.go
package main
func main() {
fmt.Println("hello")
}
// test2.go
package main
func main() { // ❌ 编译错误:重复定义 main
fmt.Println("world")
}
8.2 原因
每个程序只有一个入口(main函数),Go 编译器不允许同一个包中存在多个 main 函数。
8.3 解决方案
将不需要编译的文件改名为 .txt 或其他后缀,使其不被编译:
test1.go → 正常编译
test2.go → 改为 test2.txt(不参与编译)
九、本讲小结
| 知识点 | 要点 |
|---|---|
| OS.Args | 接收命令行参数,返回 []string |
| 未使用包/变量 | 编译报错(Go的安全机制) |
| 变量声明 | 类型在变量名后面 |
| 两种声明方式 | var name type 和 name := value |
| 无分号 | Go 不需要分号,IDE自动格式化 |
| For循环 | Go 只有 for,无 while |
| 格式化输出 | Print / Println / Printf(类似C语言) |
| go build | 编译生成可执行文件,可带参数运行 |
| 多返回值 | Go 函数可返回多个值(Java做不到) |
| error返回值 | 类似Java异常,但不使用try-catch |
| main唯一性 | 同一包内只能有一个 main 函数 |
十、课后练习
- 编写程序,接收命令行参数并将所有参数用空格拼接后输出
- 尝试使用
fmt.Printf输出不同类型的数据(整数、字符串、浮点数) - 编写一个返回两个值的函数(如返回商和余数),并用两个变量接收
- 尝试在同一目录下创建两个含 main 函数的 .go 文件,观察编译错误