Go 语言入门笔记:变量声明、同包/跨包引用、输入输出与 fmt 格式化

这两天事比较多,但是也在复习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 个条件

跨包引用核心规则:

  1. 被引用的标识符首字母必须大写(导出)

  2. 要 import 目标包(导入路径通常是 模块名/目录名

  3. 使用时必须写 包名.标识符

目录结构示例:

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,可以按这篇先把基础打牢,后面写项目会顺很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值