这两天事比较多,但是也在复习go语言,在复习过程中总感慨它很多设计都“简单但有规则”。这篇我着重讲解这几个板块:变量声明、同包/跨包引用、输入输出、以及 fmt.Printf / fmt.Sprintf 的用法。
目录
一、Go 的 5 种变量声明方式
Go 的变量声明看似花样多,但核心就一句:该明确的时候明确,该省略的时候省略。
1)标准声明(显式指定类型)
适合:我想让类型一眼看清,或者需要在全局声明。
var age int = 18
var name string = "Cory"
特点:
-
var 变量名 类型 [= 初始值] -
函数内/外都能用
-
可读性高
2)类型推导声明(省略类型)
适合:初始化值很明确,类型交给 Go 推导。
var age = 18 // int
var pi = 3.14 // float64
var ok = true // bool
特点:
-
var 变量名 = 值 -
函数内/外都能用
-
比标准声明更简洁
3)短变量声明(函数内最常用)
适合:日常写业务逻辑,基本离不开它。
func main() {
age := 18
name := "Cory"
fmt.Println(age, name)
}
特点:
-
变量名 := 值 -
只能在函数/方法里用(全局不行)
-
必须赋值(不能只写
a :=) -
可以“重复声明”,但必须至少出现一个新变量:
func main() {
a := 10
a, b := 20, "new" // ✅ a 复用,b 是新变量
fmt.Println(a, b)
}
4)批量声明(var ())
适合:一次声明多个变量,尤其是全局变量更清爽。
var (
host string = "127.0.0.1"
port int = 8080
debug = true
)
5)零值声明(只声明不赋值)
适合:先占坑,后面再赋值。
var score int
var title string
var flag bool
fmt.Println(score, title, flag) // 0 "" false
Go 会自动给变量一个“零值”,不同类型零值不同。
变量声明方式对比表
| 方式 | 写法 | 是否必须赋值 | 是否可用于全局 | 常用程度 |
|---|---|---|---|---|
| 标准声明 | var a int = 1 | 否 | 是 | 中 |
| 类型推导 | var a = 1 | 是 | 是 | 中 |
| 短变量声明 | a := 1 | 是 | 否 | 最高 |
| 批量声明 | var ( ... ) | 否 | 是 | 高 |
| 零值声明 | var a int | 否 | 是 | 高 |
二、同包引用 vs 跨包引用(导入与导出)
这块我刚开始真的踩坑:同包随便用,跨包要讲规矩。
1)同包(不跨包)引用:直接用就行
核心规则:
-
同一目录下的
.go文件 必须是同一个包名(比如都package main) -
同包内标识符 不管首字母大小写都能互相用
-
不需要 import
目录结构示例:
project/
main.go
common.go
common.go
package main
var msg = "hello"
func add(a, b int) int { return a + b }
main.go
package main
import "fmt"
func main() {
fmt.Println(msg)
fmt.Println(add(1, 2))
}
2)跨包引用:必须满足 3 个条件
跨包引用核心规则:
-
被引用的标识符首字母必须大写(导出)
-
要 import 目标包(导入路径通常是
模块名/目录名) -
使用时必须写
包名.标识符
目录结构示例:
hello/
go.mod // module hello
main.go
version/
version.go
version/version.go
package version
var Version = "v1.0.0" // 首字母大写,才能跨包用
main.go
package main
import (
"fmt"
"hello/version"
)
func main() {
fmt.Println(version.Version)
}
跨包常见坑(我最常遇到的)
-
imported and not used:导入了但没用,Go 会直接报错 -
同一目录里写了不同包名:会编译失败
-
变量首字母小写:跨包访问不到(这是最经典的“为什么用不了”)
三、输入输出:控制台 + 文件(必须会的基础)
Go 的 IO 我分两块:控制台输入输出、文件读写。
1)控制台输出(fmt 最常用)
常见打印:
fmt.Print("hello") // 不换行
fmt.Println("hello") // 自动换行
fmt.Printf("age=%d\n", 18) // 格式化输出
常用占位符(新手先背这几个):
| 占位符 | 含义 | 例子 |
|---|---|---|
%s | 字符串 | "Tom" |
%d | 整数 | 20 |
%f | 浮点数 | 3.14 |
%.2f | 保留两位小数 | 3.14159 -> 3.14 |
%T | 打印类型 | int/string... |
%v | 通用兜底 | 大多数都能打印 |
2)控制台输入(fmt.Scan / Scanln)
关键点:必须传地址 &变量,不然赋值不进去。
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("输入姓名和年龄:")
fmt.Scan(&name, &age) // & 不能忘
fmt.Printf("name=%s age=%d\n", name, age)
}
注意:
Scan系列会按空格/换行分隔,所以输入带空格的内容会被截断。
3)读取整行输入(解决 Scan 遇空格截断)
如果要读一整行(比如“张三 李四”),用 bufio:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("请输入一整行:")
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line) // 去掉末尾换行
fmt.Println("你输入的是:", line)
}
4)文件输出(写入文件)
最基础写法:
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Create("out.txt")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()
fmt.Fprintln(file, "hello file")
fmt.Fprintln(file, "第二行内容")
}
5)文件输入(读取文件)
小文件直接 os.ReadFile 很爽:
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("out.txt")
if err != nil {
fmt.Println("读取失败:", err)
return
}
fmt.Println(string(data))
}
IO 必须养成的三个习惯
-
err 必判断:读写文件、输入输出都可能失败
-
文件必关闭:
defer file.Close() -
Scan 必传地址:
fmt.Scan(&x)
四、Tips:Printf 换行的两种写法
我之前写:
fmt.Printf(name)
printNum()
结果俩输出粘在一行,很烦。解决有两种:
方法 1:在 Printf 里加 \n(推荐)
fmt.Printf("%s\n", name)
printNum()
方法 2:改用 Println(更省事)
fmt.Println(name)
printNum()
五、fmt.Sprintf:不打印,只“拼字符串”
很多人第一次看到 Sprintf 会疑惑:它不输出,那有什么用?
我的理解:Sprintf 就是“先把字符串拼好”,后续你想打印、写文件、存日志都行。
1)核心区别:Printf vs Sprintf
-
fmt.Printf(...):直接打印到控制台 -
fmt.Sprintf(...):返回格式化后的字符串
2)最常见的使用场景
-
拼接多变量信息(比如姓名 + 版本号)
-
组装日志,再统一写入文件
-
避免到处
Println,先拼好再一次输出
3)最简示例
package main
import "fmt"
func main() {
name := "张三"
version := "v1.0.0"
info := fmt.Sprintf("姓名:%s,版本:%v\n", name, version)
fmt.Print(info) // 这里你想打印 or 写文件都行
}
注意点:
-
Sprintf必须接收返回值,只写fmt.Sprintf(...)是没效果的 -
占位符要匹配类型(比如
%d别去套字符串)
六、总结
-
变量声明:日常最常用的是
:=,但要记住它只能在函数内;需要更清晰或全局时用var。 -
包引用:同包直接用;跨包必须满足:首字母大写导出 + import + 包名.标识符。
-
输入输出:
fmt.Scan记得&;读取整行用bufio;文件操作一定要err判断 +defer Close()。 -
格式化:
Printf负责打印,Sprintf负责拼字符串;换行要么\n,要么Println。
如果你也在学 Go,可以按这篇先把基础打牢,后面写项目会顺很多。

1064

被折叠的 条评论
为什么被折叠?



