💜 想真正擅长编程? 从一门课程开始,100% 免费

《笔记》第五篇 实现Go的参数接收

第05讲 实现Go的参数接收

本讲义根据视频实际讲解内容整理,涵盖命令行参数接收、OS包使用、变量声明、格式化输出、多返回值函数等核心知识点。


一、命令行参数概述

1.1 什么是命令行参数

在Java中,我们使用 args 来接收命令行参数:

Java
public static void main(String[] args) {
    // Java中的args
}

Go语言中同样需要接收命令行参数,但需要借助 OS包 来实现:

Go
package main

import (
    "os"
)

func main() {
    // 通过 os.Args 接收命令行参数
}

1.2 OS包的特点

  • OS 是 Go 语言的内置标准库,不需要手动安装
  • 导入方式:使用 import "os"
  • 多个包导入时,使用括号包裹:
Go
import (
    "os"
    "fmt"
)

二、OS.Args 详解

2.1 编译安全机制

在Go中,如果你导入了一个包但没有使用它,编译会报错:

Go
import (
    "os"    // 如果没用到 os,编译报错!
    "fmt"
)

老师强调:这是Go语言为了代码安全性和避免资源浪费而设计的机制——未使用的包和变量必须去掉,否则无法编译通过。

2.2 OS.Args 的返回值

os.Args 返回一个 string 类型的数组(切片):

Go
// os.Args 的类型:[]string
args := os.Args

2.3 获取参数长度

使用 len() 函数计算数组长度:

Go
length := len(os.Args)

三、变量声明与初始化

3.1 Go变量声明的特点

Go语言的变量类型在变量名的后面(与Java/C相反):

Go
// Go 的写法(类型在后)
var str string
var i int

// Java 的写法(类型在前)
// String str;
// int i;

3.2 两种变量声明方式

方式一:传统 var 声明

Go
var str string = "hello"
var i int = 0

方式二:短变量声明(:=)

Go
str := "hello"
i := 0

3.3 不需要分号

Go语言中不需要写分号,保存时IDE会自动格式化并移除多余的分号:

Go
// 写了分号也能编译,但保存后自动消失
var str string = "hello";  // 保存后 → var str string = "hello"

四、For循环与参数拼接

4.1 传统For循环

Go只有 for 关键字,没有 while,但 for 可以实现所有循环需求:

Go
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 字符串拼接

使用 += 进行字符串拼接:

Go
str += os.Args[i] + " "

4.3 格式化输出

Go 提供了三种打印函数,类似于 C 语言的 printf:

函数 说明 示例
fmt.Print() 原样输出,不换行 fmt.Print("hello")
fmt.Println() 输出后自动换行 fmt.Println("hello")
fmt.Printf() 格式化输出 fmt.Printf("你好,我是%s", "小明")

格式化占位符:

Go
fmt.Printf("%d", 100)      // 整数
fmt.Printf("%s", "hello")  // 字符串
fmt.Printf("%f", 3.14)     // 浮点数

注意:%d 只能用于整数,不能放字符串,否则会出错。这与 C 语言的 printf 用法一致。


五、编译与运行

5.1 go build 编译

编译后生成可执行文件,可以带参数运行:

Shell
# 编译
go build

# 运行(带参数)
./demo param1 param2 param3

老师类比:这类似于 Docker 的用法——docker run -itd --name mycontainer ubuntu /bin/bash,命令后面跟参数,程序根据参数执行不同逻辑。

5.2 实际应用场景

老师举了一个实际例子——启动 GoGhost 时带 web 参数:

Shell
# 带 web 参数启动 Web 服务
./goghost web

程序通过判断参数来决定启动哪种服务。这就是命令行参数的实际用途:程序启动时根据参数执行不同功能。


六、短变量声明(:=)的限制

6.1 := 不能在函数外使用

Go
// ✅ 函数内可以使用 :=
func main() {
    str := "hello"  // 正确
}

// ❌ 函数外不能使用 :=
str := "hello"  // 编译错误!

6.2 := 与多返回值

短变量声明 := 在函数返回多个值时特别有用:

Go
// Go 的函数可以返回多个值(Java做不到)
func test() (string, int) {
    return "hello", 100
}

func main() {
    // 两个变量接收两个返回值
    str, num := test()
    fmt.Println(str, num)
}

重点:如果前面定义了两个变量,函数也必须返回两个值,一一对应,数量不匹配会报错。


七、OS包其他功能预览

OS 包不仅有 Args,还包含丰富的文件操作功能:

Go
// 文件信息结构体
type FileInfo struct {
    // ...
}

// 文件模式
type FileMode int

// 打开文件
func Open(name string) (*File, error)

// 读取文件内容
func ReadFile(name string) ([]byte, error)

7.1 error 返回值

Go 的文件操作函数通常会返回一个 error 类型的值:

Go
data, err := os.ReadFile("test.txt")
if err != nil {
    // 处理错误
}

老师说明:这类似于 Java 中的抛出异常,但 Go 不使用 try-catch,而是通过返回值来传递错误信息。

7.2 结构体概念预览

Go
type File struct {
    // 内部字段
}

老师提到:type File struct 定义了一个结构体,*File 是指向结构体的指针,后续课程会详细讲解。


八、常见问题:多个 main 函数冲突

8.1 问题现象

如果一个目录下有两个 .go 文件都包含 func main(),编译会报错:

Go
// 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 或其他后缀,使其不被编译:

TEXT
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 函数

十、课后练习

  1. 编写程序,接收命令行参数并将所有参数用空格拼接后输出
  2. 尝试使用 fmt.Printf 输出不同类型的数据(整数、字符串、浮点数)
  3. 编写一个返回两个值的函数(如返回商和余数),并用两个变量接收
  4. 尝试在同一目录下创建两个含 main 函数的 .go 文件,观察编译错误