惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
T
ThreatConnect
SecWiki News
SecWiki News
F
Future of Privacy Forum
AWS News Blog
AWS News Blog
C
Cisco Blogs
A
Arctic Wolf
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
V2EX
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
K
Kaspersky official blog
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
NISL@THU
NISL@THU
Microsoft Azure Blog
Microsoft Azure Blog
量子位
The Hacker News
The Hacker News
Stack Overflow Blog
Stack Overflow Blog
Security Latest
Security Latest
M
Microsoft Research Blog - Microsoft Research
Google Online Security Blog
Google Online Security Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
InfoQ
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
F
Fox-IT International blog
S
Security @ Cisco Blogs
博客园 - 司徒正美
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Comments on: Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LINUX DO - 最新话题
GbyAI
GbyAI
Project Zero
Project Zero
腾讯CDC
T
Tailwind CSS Blog

博客园_首页

给热水器装上“电量显示”:用 Shelly Gen4 脚本实现零改装水量预测 踩坑实录:接口正常Feign调用字段值为空 耿同学学术打假,就是学术版《狂人日记》;学术打假,就是清扫垃圾 浙江事业编笔试上周出分!面试进入倒计时,该如何高效冲刺 - 里奥不吃奥利奥 FastApiAdmin 后端接口开发好了,前端管理界面怎么调用与显示? 我写了 50 个 Claude Code Skill 才发现,前 30 个都白写了 告别 "cd /var/log" !用 journalctl 统一掌控 Linux 日志 我用自己的微信聊天记录,微调了一个“数字分身” AI运动APP开发的常见问题集锦一 复盘梳理-如何深入并抽象 告别手动复制!公众号文章批量导出工具,极致提升内容运营效率 【学习笔记】《Python编程 从入门到实践》第2章:变量命名规则、字符串操作与数值类型详解 Docker--Docker简介及系统架构 别再瞎搞 AI 了!大厂AI业务落地的五个关键环节!(建议新手直接照搬) [MAF的Agent管道详解-01]塑智能体边界,从AIAgent抽象类开始 平台智能化到了分水岭:为什么配置代码化才是 AI Coding 的下一代接口 P.4文本统计工具 高光谱拼接算法(二)Harris 角点探测 - 哥布林学者 Claude Code “悄悄”装了 Python 包?别再让它“投错胎”了 - only赟 影刀 vs 八爪鱼 RPA:到底选哪个?一篇讲透 AI Coding开始进入第四个时代,我还没上车呢! 完整学习LLM(四):Token是什么 【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (1)---基础 LitCTF2026web部分wp CAD子系统,是自研还是外包? 什么是教程地狱?5个信号说明你已经陷入(附3步摆脱方法) polygon出题教程 Manim物理模拟:别自己写欧拉了! AI 学习笔记:Agent 的应用演示 - 凌杰 分享一个CAN报文编辑器软件 洛谷P13016 [GESP202506 六级] 最大因数 MiniCPM-V 4.6 部署实战:基于 GPUStack 与 SGLang 的端侧多模态模型部署 用 FRP 打通云服务器与本地 Ubuntu,让 Codex 远程调试本地硬件 软考 - 架构设计师 知识点总结 给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍 聊一聊 MES系统如何实现多种标签打印并支持不同打印机 2026第四届LitCTF网络安全挑战赛Pwn的wp 断尺问题:戴德金分割现实悖论 给句子做个“语义审计”:从词向量到句子向量的方法论 当AI“卡壳”在生产环境:MCP Server 如何帮我们破局 ofdkit-harmony 0.2.0 发布:鸿蒙原生 OFD 阅读库,已上架 ohpm 有了AI测试工具,还需要掌握Playwright、Pytest、Selenium这些框架吗? 组织转型实录——我把传统研发团队改成AI驱动,踩了无数坑 为什么 AI Coding 难进生产环境?深入了解 Everything-Claude-Code ! 到底 TMD 用哪个: npm, pnpm, Yarn, Bun, Deno? 傻瓜, 当然用 npm 啦 上周热点回顾(5.18-5.24) [对比学习LangChain和MAF-04]针对消息的设计 TrueAsync Server 为 PHP 带来了原生的高性能 HTTP 服务器 规则漂移 帆软市场部为什么能成为高人效增长系统? 22. LangChain LCEL,用 | 串联AI的魔法语言 - 老陈说编程 完整学习LLM(二):大模型到底是什么 洛谷-P11942 [KTSC 2025] 重塑矩阵 题解 哈哈哈哈哈打不过我吧,没有办法我(vllm)就是这么强大! Hermes Edu Skills 从 170 到 188:一次中文教育 Agent Skill Pack 的工程化升级 一个外行,半年搞定机械臂:我的从0到1踩坑实录 新写了个直播录制工具,可录制抖音快手斗鱼直播 15天学会AI应用开发(一)搭建AI大模型应用开发环境 Childhood,23款童年卡牌游戏复刻 Github Copilot配置GPT5.5报错:'temperature' does not support 0.1 with this model. Only the default (1) value is supported. - Eric zhou 单曲循环 ClassIn 在 Linux 下无法播放音频 把 TeXstudio / LaTeX 工程交给 AI:texstudio-mcp 功能详解 .NET 8 Web开发入门(六):Blazor 全栈开发——告别 JavaScript 焦虑 别让 LLM 写文件:一套 Agent 进度跟踪的工程化范式 - BurningFish Qt Bridges for C# 深度技术解析 Multus 多网卡方案:IPVLAN 模式 被流量逼出来的架构:从一台服务器到云原生的 17 次蜕变 —— 集群、缓存、MQ、微服务、Docker、K8S 的前世今生 Claude Code安装全流程 Windows保姆级教程 awk 命令练习(从入门到进阶) Java + Spring实现Hermes Agent之龙虾、Skills、Mcp和沙箱代码执行环境思路 轨迹的蓝图:方程求解与交点计算 Agent新技术分享-Forge论文已被ACM接受 PowerMem 记忆系统的遗忘设计,从神经元到代码工程 我用了FastApiAdmin后,连夜把踩过的坑都整理出来了 一个程序员眼中的 AI 核心概念,讲透 LLM 、Agent 、MCP 、Skill 、RAG... 网络安全在线就能打的内网靶场推荐 & Dawn Breaker 单域靶场 WP CTF 中如何用提示词发挥大模型的最大实力:从聊天助手到大手子 PyTorch KernelAgent 源码解读 ---(6)--- Composer 高光谱拼接算法(一)扫推式成像和航带拼接算法 一文看懂fofa常用语法,告别混淆,精准打击! 从零搭建量化投资系统:用 Qlib 一行代码搞定均线分析 企业 AI 落地,第一件事不是买模型,而是建好企业知识库 如何在Oracle Agent Factory中配置国内厂商的LLM? Codex 换模型太麻烦?这个开源桌面工具帮你一键切换 Avalonia中的动画 2026软考|十大管理超全通俗笔记,备考闭眼记! rv1126b内置phy接hub交换机芯片 React 可拖拽列宽 + 点击行选中 ProTable 封装笔记 五大实锤证据:AI不会终结低代码,只会倒逼技术进化 【硬核脑洞】16位实模式最后的疯狂:我们能否在 640KB 常规内存里手搓一个 MD 模拟器? 基于.Net的NetCoreKevin框架中AgentFramework实现AI智能体Skill和工具动态管理和加载 PostgreSQL 高可用集群 patroni 自动故障转移测试 自己使用C++开发的仿OpenClaw、Hermes智能体工具 记一次 .NET 某集群管理软件 内存暴涨分析 StarBlog番外(5) 从1.6到1.10,基于Avalonia AOT 开发的 Publisher 半年进化之路 Anthropic 把 SOC 误报率从 33% 砍到 7%,真正在干活的不是 Claude SM2演示所有 PEM 功能(生成、加解密、签名/验签) 用 Solon AI 从零构建 MCP 工具服务:让 AI Agent 拥有真实世界的能力 完整学习LLM(一):为什么我要系统学习大模型
Go 语言入门学习笔记基础版
okkk!!! · 2026-05-26 · via 博客园_首页

Go 语言入门学习笔记基础版

文档说明

本文档整合阶段性全部学习内容,包含基础语法、输入输出、流程控制、数组/切片、函数、Map、结构体、方法、指针等核心知识点,搭配代码示例、场景说明、易错提醒与实战练习,适合系统复习与查阅。


1. 程序基础结构

1.1 标准可执行程序模板

所有 Go 可执行文件固定格式:

package main

import "fmt"

func main() {
    // 业务代码写在这里
}
  • package main:声明为主包,代表当前文件是可执行程序,而非库文件
  • import "fmt":导入标准输入输出包,用于打印、读取控制台内容
  • func main():程序入口函数,程序运行时自动执行,无参数、无返回值

2. 输入与输出

2.1 三类标准打印函数(fmt 包)

函数 是否自动换行 参数间自动加空格 支持格式化占位符 适用场景
fmt.Print() 连续拼接简单内容
fmt.Println() 日常常规打印(使用最多)
fmt.Printf() 格式化输出、变量拼接

常用格式化占位符

  • %d:十进制整数
  • %s:字符串
  • %f:浮点数;%.2f 表示保留 2 位小数
  • %v:通用占位符,可打印任意数据类型

示例代码

package main

import "fmt"

func main() {
    name := "张三"
    age := 20
    fmt.Printf("姓名:%s,年龄:%d\n", name, age)
}

2.2 内置原生打印函数

print() / println()

  • 无需导入 fmt 包,Go 语言内置
  • 功能简单,仅用于临时调试
  • 正式项目、生产环境禁止使用
println("临时调试信息")

2.3 控制台输入 fmt.Scan

作用:接收用户在控制台输入的数据。

基础语法

var 变量名 数据类型
fmt.Scan(&变量名)

核心规则

  • 必须添加 &(取地址符),否则编译报错
  • 支持一次性读取多个值,输入时用空格 / 回车分隔

示例

package main

import "fmt"

func main() {
    var num int
    fmt.Print("请输入一个数字:")
    fmt.Scan(&num)
    fmt.Println("你输入的数字:", num)

    // 一次性读取多个值
    var a, b int
    fmt.Scan(&a, &b)
    fmt.Println(a, b)
}

3. 变量基础

3.1 变量定义与初始化

完整写法

var 变量名 数据类型
var name string
var num int

定义并赋值

var age int = 18

类型推导(简写,推荐)

无需手动声明类型,编译器自动推断。

sex := "男"

3.2 变量使用规则

  • 定义后的变量必须使用,否则编译报错
  • 变量名区分大小写
  • 同一代码块内,变量名不能重复定义

4. 条件判断

4.1 if / else 分支判断

基础单分支

if 条件表达式 {
    // 条件成立执行代码
}

双分支 if-else

if 条件表达式 {
    // 条件成立
} else {
    // 条件不成立
}

多分支 else if

if score >= 90 {
    fmt.Println("优秀")
} else if score >= 60 {
    fmt.Println("及格")
} else {
    fmt.Println("不及格")
}

实战示例:判断奇偶数

package main

import "fmt"

func main() {
    var num int
    fmt.Scan(&num)
    if num%2 == 0 {
        fmt.Println("偶数")
    } else {
        fmt.Println("奇数")
    }
}

4.2 switch 分支语句

Go 语言 switch 默认自带 break,匹配成功后自动终止,无需手动添加。

写法 1:带表达式(等值匹配)

switch 变量/表达式 {
case 值1:
    逻辑代码
case 值2:
    逻辑代码
default:
    // 所有case都不匹配时执行
}

示例:简易菜单选择

package main

import "fmt"

func main() {
    var op int
    fmt.Println("1.加法  2.减法")
    fmt.Scan(&op)

    switch op {
    case 1:
        fmt.Println("执行加法运算")
    case 2:
        fmt.Println("执行减法运算")
    default:
        fmt.Println("输入选项错误")
    }
}

写法 2:无表达式(替代多 if 判断)

score := 85
switch {
case score >= 90:
    fmt.Println("优秀")
case score >= 60:
    fmt.Println("及格")
default:
    fmt.Println("不及格")
}

补充规则

  • 一个 case 可匹配多个值:case 1,2,3:
  • default 可选,建议写在所有 case 最后

5. 循环结构(Go 仅支持 for)

Go 语言没有 while、do-while,所有循环统一使用 for 实现。

5.1 四种常用 for 写法

写法 1:标准三段式(计数循环,最常用)

for 初始化语句; 循环条件; 后置语句 {
    循环体
}

示例:打印 1 ~ 10

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

写法 2:仅保留条件(等效 while 循环)

i := 1
for i <= 10 {
    fmt.Println(i)
    i++
}

写法 3:死循环

for {
    // 无限循环,必须配合 break 退出
}

写法 4:for range 遍历(数组 / 切片 / Map 专用)

for 索引, 值 := range 容器 {

}

5.2 匿名变量 _

遍历场景中,不需要使用索引时,用 _ 占位,避免「定义变量未使用」编译报错。

nums := []int{1, 2, 3, 4}
for _, v := range nums {
    fmt.Println(v)
}

5.3 循环控制关键字

break

跳出当前所在循环,直接终止循环执行。

for i := 1; i <= 10; i++ {
    if i == 5 {
        break
    }
    fmt.Println(i)
}

continue

跳过本次循环剩余代码,直接进入下一次循环。

for i := 1; i <= 10; i++ {
    if i == 5 {
        continue
    }
    fmt.Println(i)
}

5.4 双层嵌套循环

  • 外层循环:控制行数
  • 内层循环:控制每行内容

示例 1:打印直角三角形

for i := 1; i <= 5; i++ {
    for j := 1; j <= i; j++ {
        fmt.Print("* ")
    }
    fmt.Println()
}

示例 2:九九乘法表

for i := 1; i <= 9; i++ {
    for j := 1; j <= i; j++ {
        fmt.Printf("%d*%d=%d\t", j, i, i*j)
    }
    fmt.Println()
}

6. 数组与切片

6.1 数组(长度固定)

定义语法

var 数组名 [长度]数据类型
var arr [3]int

多种初始化方式

// 1. 先定义,后赋值
var a [3]int
a[0] = 10
a[1] = 20

// 2. 定义同时赋值
var b [3]int = [3]int{1, 2, 3}

// 3. 自动推导长度 ...(仅定义+初始化时可用)
c := [...]int{4, 5, 6}

数组核心特点

  • 长度在编译阶段确定,定义后无法修改
  • 元素下标从 0 开始
  • 属于值类型,赋值、函数传参时会完整拷贝数据

易错点var arr [...]int 单独声明数组写法非法,编译器无法推断长度。

6.2 切片 Slice(动态数组,开发首选)

切片基于数组实现,长度可变,实际开发优先使用切片。

定义与初始化

// 1. 声明空切片
var s1 []int

// 2. 直接初始化元素
s2 := []int{1, 3, 5, 7}

// 3. make 创建切片(参数:长度, 容量)
s3 := make([]int, 2, 5)

核心操作:append 追加元素

空切片不能直接通过下标赋值,必须使用 append 动态追加元素:

var s []int
s = append(s, 10)
s = append(s, 20, 30)
fmt.Println(s)

切片截取

语法:切片[起始下标:结束下标],含左不含右

s := []int{10, 20, 30, 40}
part := s[1:3]
fmt.Println(part) // 输出 [20 30]

切片易错写法

var s []int
s[0] = 10 // 运行报错:下标越界,空切片长度为0

7. 函数

7.1 基础函数

语法格式

func 函数名(参数列表) 返回值类型 {
    函数体
    return 返回值
}

示例:两数求和

func add(a int, b int) int {
    return a + b
}

7.2 多返回值(Go 语言特色)

一个函数可以同时返回多个结果。

// 返回两数之和、两数之差
func calc(a, b int) (int, int) {
    return a + b, a - b
}

func main() {
    sum, sub := calc(10, 4)
    fmt.Println(sum, sub)

    // 匿名变量 _ 忽略不需要的返回值
    _, sub2 := calc(20, 7)
    fmt.Println(sub2)
}

7.3 可变参数

格式:参数名 ...数据类型,支持传入任意个数同类型参数,函数内部按切片处理。

// 对任意个整数求和
func sum(nums ...int) int {
    total := 0
    for _, v := range nums {
        total += v
    }
    return total
}

func main() {
    fmt.Println(sum(1, 2))
    fmt.Println(sum(1, 2, 3, 4))
}

7.4 匿名函数

无函数名,可定义后立即执行,也可赋值给变量调用。

func main() {
    // 写法1:定义并立即执行
    func(a, b int) {
        fmt.Println(a * b)
    }(3, 5)

    // 写法2:赋值给变量,重复调用
    f := func(x int) {
        fmt.Println(x * x)
    }
    f(6)
}

8. Map 键值对(字典)

存储 key-value 格式数据,键唯一,遍历顺序无序。

8.1 定义与初始化

Map 必须使用 make 初始化,未初始化直接赋值会报错。

// 格式:map[键类型]值类型
user := make(map[string]string)

// 新增 / 修改元素(key存在则覆盖,不存在则新增)
user["name"] = "张三"
user["age"] = "20"

8.2 取值 + 判断 Key 是否存在

Map 获取不存在的键,不会报错,会返回对应类型零值。通过第二个返回值 ok 判断键是否真实存在。

age, ok := user["name"]
if ok {
    fmt.Println("键存在,值:", age)
} else {
    fmt.Println("该键不存在")
}
  • age:key 对应的值
  • ok:布尔类型,true = 键存在,false = 键不存在

8.3 删除元素

使用内置函数 delete(map对象, key)

delete(user, "name")

8.4 Map 遍历

for k, v := range user {
    fmt.Println(k, ":", v)
}

9. 结构体 struct

结构体用于封装一组不同类型的数据,自定义现实事物模型。

9.1 结构体定义

type 结构体名 struct {
    字段名 字段类型
}

type Student struct {
    Name string
    Age  int
}

9.2 结构体实例化与赋值

func main() {
    // 方式1:键值对赋值(推荐,可读性强)
    s1 := Student{
        Name: "小明",
        Age:  18,
    }

    // 方式2:按字段顺序赋值
    s2 := Student{"小红", 19}

    // 访问结构体字段
    fmt.Println(s1.Name, s1.Age)
}

10. 结构体方法

方法是绑定在结构体上的函数,分为「值接收者」和「指针接收者」。

10.1 值接收者

func (接收者变量 结构体类型) 方法名() {}
  • 调用时会拷贝结构体副本
  • 无法修改原结构体数据
  • 适用场景:只读查询、打印信息、数值计算
type Person struct {
    Name string
    Age  int
}

// 只读方法:值接收者
func (p Person) GetName() string {
    return p.Name
}

// 反面示例:尝试用值接收者修改数据(无效)
func (p Person) Rename(newName string) {
    p.Name = newName // 仅修改副本,原数据不变
}

10.2 指针接收者

func (接收者变量 *结构体类型) 方法名() {}
  • 直接操作原结构体内存地址
  • 可以修改原结构体数据
  • 适用场景:更新 / 修改字段;结构体较大时,减少拷贝开销
// 可修改数据:指针接收者
func (p *Person) SetName(newName string) {
    p.Name = newName
}

10.3 选用口诀

  • 只读取数据 → 使用 值接收者
  • 需要修改数据 / 结构体体积大 → 使用 指针接收者

11. 指针基础

11.1 两个核心符号

  • &:取地址符,获取变量的内存地址
  • *:解引用符,根据地址读写对应的值

11.2 基础使用

func main() {
    a := 10
    fmt.Println("变量a的地址:", &a)

    // 定义指针变量,存储 int 类型地址
    var p *int
    p = &a

    // 通过指针修改原变量值
    *p = 20
    fmt.Println("修改后 a 的值:", a)
}

11.3 指针作为函数参数

Go 函数参数默认值传递,普通传参只能修改副本;使用指针传参可直接修改外部原变量。

普通传参(无法修改原值)

func change(num int) {
    num = 100
}

指针传参(可修改原值)

func change(num *int) {
    *num = 100
}

func main() {
    x := 10
    change(&x)
    fmt.Println(x) // 输出 100
}

12. 全套实战练习题

基础练习

  • 循环顺序打印 1 ~ 10
  • 计算 1 ~ 100 所有数字累加和
  • 输入数字,判断奇数 / 偶数
  • 筛选 1~100 中所有偶数、能被 3 整除的数字

进阶练习

  • 双层循环:打印直角三角形、九九乘法表
  • 猜数字小游戏(for + if + break)
  • 切片遍历、切片求和、求切片最大值与最小值
  • 简易菜单计算器(Scan + switch + 函数)
  • 学生信息管理(结构体 + Map + 方法)

13. 高频易错点汇总

  1. fmt.Scan 传参必须加 &,漏写直接编译报错
  2. 空切片不能直接下标赋值,必须使用 append 追加元素
  3. 数组 [...] 语法,仅能在定义并初始化时使用
  4. for range 遍历返回索引和值,无用索引必须用 _ 占位
  5. Map 必须先用 make 初始化,未初始化无法赋值
  6. Map 取值搭配 ok 判断 key 是否存在,区分零值与键不存在
  7. 结构体方法:修改数据用指针接收者,只读逻辑用值接收者
  8. Go 的 switch 默认自带 break,不会顺序穿透
  9. 变量定义后必须使用,否则编译报错