【Go】P3 Go语言程序结构

Go语言程序结构

  • Go语言程序结构
    • 命名规则与编程惯例
    • 核心规则
    • 四种声明语句详解
      • var声明:变量声明
      • const声明:常量声明
      • type声明:类型定义
      • func声明:函数声明
    • 简短变量声明(:=)
      • 使用规则和限制
    • 指针:安全的内存地址操作
      • 基本概念和操作
      • 结构体指针的自动解引用
    • new函数与内存分配
      • new vs make的区别
    • 变量生命周期与内存管理
      • 生命周期规则
    • 赋值操作与元组赋值
    • 包管理与文件组织
      • 包声明与导入
      • 包的初始化与init函数
      • 执行顺序
    • 作用域规则详解
      • 作用域层级
      • 变量遮蔽示例

Go语言程序结构

命名规则与编程惯例

Go语言通过简洁的命名规则实现了代码的清晰性和可维护性。


核心规则

导出机制:首字母大小写决定标识符的可见性

  • 首字母大写:导出的(公开),包外可访问
  • 首字母小写:未导出的(私有),仅包内可访问
  • 例如:fmt 包的 Printf 函数就是导出的,可以在fmt包外部访问

命名风格:采用驼峰命名法,避免下划线

package main// 导出的变量和函数(首字母大写)
var PublicVar int = 100
func PublicFunction() {fmt.Println("可以被其他包调用")
}// 未导出的变量和函数(首字母小写)
var privateVar string = "private"
func privateFunction() {fmt.Println("仅本包内可用")
}// 良好的命名示例
var userName string        // 驼峰命名
var HTTPClient *http.Client // 缩写词保持大写
const MaxConnections = 100  // 常量

实践要点

  • 包名使用小写单词,简洁明了
  • 常量名要有意义,不基于数值命名
  • 缩写词保持一致的大小写(URL、HTTP、JSON)

四种声明语句详解

Go语言提供四种声明语句,每种都有特定的用途和语法规则。

var声明:变量声明

// 基本语法
var age int                 // 声明,使用零值
var name string = "Go"      // 声明并初始化
var score = 95.5            // 类型推断// 批量声明
var (width  int = 100height int = 200title  string = "Go编程"
)// 多变量声明
var x, y int = 10, 20

零值机制:未初始化变量自动设置为类型对应的零值

  • 数值类型:0
  • 布尔类型:false
  • 字符串:“”
  • 指针、切片、映射:nil

const声明:常量声明

// 基本常量
const Pi = 3.14159
const AppName string = "MyApp"// 常量组
const (StatusOK     = 200StatusError  = 500StatusNotFound = 404
)// 无类型常量的威力
const (Big   = 1 << 100  // 1 << 100 表示将数字 1 向左位移 100 位,相当于计算 2^100Small = Big >> 99 // Big >> 99 表示将 Big 向右位移 99 位,右移 99 位后得到 2^100 / 2^99 = 2^1 = 2
)

type声明:类型定义

// 定义新类型(具有新的方法集)
type Celsius float64
type UserID int// 为新类型添加方法
func (c Celsius) String() string {return fmt.Sprintf("%.1f°C", c)
}// 类型别名(Go 1.9+)
type StringSlice = []string  // 完全等价于[]string// 复杂类型定义
type Person struct {Name stringAge  int
}type Handler func(http.ResponseWriter, *http.Request)

func声明:函数声明

// 基本函数
func add(a, b int) int {return a + b
}// 多返回值
func divmod(dividend, divisor int) (quotient, remainder int) {quotient = dividend / divisorremainder = dividend % divisorreturn  // 命名返回值可省略return后的变量名
}// 错误处理模式
func divide(a, b float64) (float64, error) {if b == 0 {return 0, errors.New("除数不能为零")}return a / b, nil
}// 变参函数
func sum(numbers ...int) int {		//numbers 是一个可变参数,意味着这个函数可以接受任意数量的 int 类型参数total := 0for _, num := range numbers {total += num}return total
}

简短变量声明(:=)

:=是Go语言的语法糖,让变量声明更加简洁。

使用规则和限制

func example() {// 基本使用name := "Go语言"           // 等价于 var name = "Go语言"count := 42               // 类型推断为int// 多变量声明x, y := 10, 20// 处理函数返回值result, err := strconv.Atoi("123")		// strconv.Atoi() 是Go标准库中的函数,用于将字符串转换为整数(ASCII to Integer的缩写)if err != nil {log.Fatal(err)}// 重新声明(至少一个新变量)result, status := calculate(), true  // result被重新声明
}

关键限制

  • 只能在函数内部使用
  • 至少要声明一个新变量
  • 会产生变量遮蔽问题

指针:安全的内存地址操作

Go语言的指针比C语言更安全,不支持指针运算。

基本概念和操作

func pointerExample() {// 基本指针操作x := 42p := &x        // p是指向x的指针fmt.Println("x的值:", x)   // 42fmt.Println("x的地址:", p) // 0x... 内存地址fmt.Println("指针指向的值:", *p) // 42// 通过指针修改值*p = 100fmt.Println("修改后x的值:", x)  // 100// 指针的零值var ptr *intfmt.Println("指针零值:", ptr)        // <nil>fmt.Println("是否为nil:", ptr == nil) // true
}// 指针作为函数参数实现引用传递
func swap(x, y *int) {*x, *y = *y, *x
}func main() {a, b := 10, 20fmt.Printf("交换前: a=%d, b=%d\n", a, b)swap(&a, &b)fmt.Printf("交换后: a=%d, b=%d\n", a, b)
}

结构体指针的自动解引用

type Person struct {Name stringAge  int
}func structPointerExample() {p := &Person{"Alice", 30}// 以下两种写法等价(自动解引用)p.Age = 31              // 简洁写法(*p).Name = "Bob"       // 显式解引用
}
  • Person{"Alice", 30}:创建一个Person实例,Name为"Alice",Age为30。
  • &:取地址操作符,获取该实例的内存地址
  • p:是一个指向Person的指针变量

new函数与内存分配

new函数用于分配内存并返回指向零值的指针。

new vs make的区别

// new: 分配零值内存,返回指针
func newExample() {p := new(int)        // 分配一块内存来存储 int 类型的值fmt.Println(*p)      // 0 (int的零值)*p = 42// 等价写法var x intp2 := &x
}// make: 用于slice、map、channel的初始化
func makeExample() {// slices := make([]int, 5)      // 长度为5的slices2 := make([]int, 5, 10) // 长度5,容量10// mapm := make(map[string]int)m["key"] = 42// channelc := make(chan int)      // 无缓冲channelc2 := make(chan int, 5)  // 缓冲区大小为5
}
  • p := new(int) 等价于 var x int; p2 := &x

  • make slice 中长度与容量的定义:

    s := make([]int, 3, 8)
    // 底层数组: [0, 0, 0, _, _, _, _, _]
    //           |<-长度3->|<--容量8-->|
    //           可访问部分    总共可用空间
    
  • 缓冲区是channel内部用来临时存储数据的空间

    ch := make(chan int, 3)  // 可以存储3个值的缓冲区
    ch <- 1  // 不阻塞
    ch <- 2  // 不阻塞
    ch <- 3  // 不阻塞
    ch <- 4  // 这里会阻塞,因为缓冲区已满
    

    无缓冲channel:适合需要严格同步的场景,如等待goroutine完成
    带缓冲channel:适合生产者-消费者模式,可以提高程序性能和解耦
    缓冲区本质上就是一个先进先出(FIFO)的队列,用来在发送方和接收方之间临时存储数据。


变量生命周期与内存管理

Go的垃圾回收器自动管理内存,但理解变量生命周期有助于写出更高效的代码。

生命周期规则

var globalVar = "全局变量"  // 程序整个生命周期func lifeCycleExample() {localVar := "局部变量"   // 函数执行期间// 变量逃逸:局部变量返回后仍被引用p := &localVarreturn p  // localVar逃逸到堆上
}func memoryExample() {// 栈分配:函数内局部变量x := 42// 堆分配:new创建或变量逃逸p := new(int)// slice在堆上分配底层数组s := make([]int, 1000)// 当这些变量不再被引用时,GC会回收内存
}

赋值操作与元组赋值

Go支持简洁的多重赋值语法。

func assignmentExample() {// 基本赋值x := 10x = 20// 元组赋值:变量交换a, b := 1, 2a, b = b, a  // 一行完成交换// 函数多返回值赋值quotient, remainder := divmod(17, 5)	//divmod 除法// 使用空白标识符忽略不需要的值// strconv.Atoi() 函数将字符串转换为整数,返回两个值:转换后的整数和可能的错误_, err := strconv.Atoi("123")  // 忽略转换结果value, _ := strconv.Atoi("456") // 忽略错误// 结构体字段赋值type Point struct { X, Y int }var p Pointp.X, p.Y = 10, 20
}

包管理与文件组织

Go程序由包组成,包是代码组织和复用的基本单元。

包声明与导入

// main.go - 主程序包
package mainimport ("fmt"                    // 标准库"net/http"              // 标准库子包"github.com/gin-gonic/gin"  // 第三方包// 导入别名f "fmt"h "net/http"// 匿名导入(仅执行init函数)_ "github.com/lib/pq"
)func main() {f.Println("使用别名导入")
}
// utils/helper.go - 工具包
package utilsimport "strings"// 导出函数(首字母大写)
func FormatName(name string) string {return strings.Title(strings.ToLower(name))
}// 未导出函数(首字母小写)
func internalHelper() {// 仅包内使用
}

包的初始化与init函数

package mainimport "fmt"// 包级变量初始化(按依赖顺序)
var config = loadConfig()// init函数:在main前执行
func init() {fmt.Println("第一个init")setupLogging()
}func init() {fmt.Println("第二个init")connectDatabase()
}func main() {fmt.Println("main函数执行")
}
  • Go允许在同一个包中定义多个init函数
  • 这些函数会在main函数之前自动执行
  • 执行顺序按照它们在源文件中出现的顺序

执行顺序

当程序运行时,执行顺序如下:

  1. 包级变量初始化:loadConfig()被调用,config变量被初始化
  2. 第一个init函数:输出"第一个init",执行setupLogging()
  3. 第二个init函数:输出"第二个init",执行connectDatabase()
  4. main函数:最后执行,输出"main函数执行"

作用域规则详解

Go语言有清晰的作用域层次结构。

作用域层级

package main  // 包作用域开始import "fmt"  // fmt在文件作用域var globalVar = "包级变量"  // 包作用域func scopeExample() {  // 函数作用域开始var functionVar = "函数变量"if true {  // 块作用域开始var blockVar = "块变量"fmt.Println(globalVar, functionVar, blockVar)// 变量遮蔽globalVar := "局部变量遮蔽全局变量"fmt.Println(globalVar)  // 打印局部变量}  // 块作用域结束// fmt.Println(blockVar)  // 错误:blockVar超出作用域fmt.Println(globalVar)  // 访问包级变量
}func anotherFunction() {fmt.Println(globalVar)  // 可以访问包级变量// fmt.Println(functionVar)  // 错误:无法访问其他函数的变量
}

变量遮蔽示例

var message = "全局消息"func shadowExample() {fmt.Println(message)  // "全局消息"message := "函数消息"  // 遮蔽全局变量fmt.Println(message)  // "函数消息"{message := "块消息"  // 遮蔽函数变量fmt.Println(message)  // "块消息"}fmt.Println(message)  // "函数消息"
}

下一篇博文,将以结构化分享 go 语言数据结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92279.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习深度学习】知识蒸馏实战:让小模型拥有大模型的智慧

目录 引言&#xff1a;模型压缩的迫切需求 一、知识蒸馏的核心原理 1.1 教师-学生模式 1.2 软目标&#xff1a;知识传递的关键 1.3 蒸馏损失函数 二、实战&#xff1a;Qwen模型蒸馏实现 2.1 环境配置与模型加载 2.2 蒸馏损失函数实现 2.3 蒸馏训练流程 2.4 训练优化技…

基于MCP提示构建工作流程自动化的实践指南

引言 在现代工作和生活中&#xff0c;我们经常被各种重复性任务所困扰——从每周的膳食计划到代码审查反馈&#xff0c;从文档更新到报告生成。这些任务虽然不复杂&#xff0c;却消耗了大量宝贵时间。MCP&#xff08;Model Context Protocol&#xff09;提示技术为解决这一问题…

apache-tomcat-11.0.9安装及环境变量配置

一、安装从官网上下载apache-tomcat-11.0.9,可以下载exe可执行文件版本&#xff0c;也可以下载zip版本&#xff0c;本文中下载的是zip版本。将下载的文件解压到指定目录&#xff1b;打开tomcat安装目录下“\conf\tomcat-users.xml”文件&#xff1b;输入以下代码&#xff0c;pa…

Java 大视界 -- Java 大数据机器学习模型在电商用户生命周期价值评估与客户关系精细化管理中的应用(383)

Java 大视界 -- Java 大数据机器学习模型在电商用户生命周期价值评估与客户关系精细化管理中的应用&#xff08;383&#xff09;引言&#xff1a;正文&#xff1a;一、电商用户运营的 “糊涂账”&#xff1a;不是所有客户都该被讨好1.1 运营者的 “三大错觉”1.1.1 错把 “过客…

豆包新模型与PromptPilot工具深度测评:AI应用开发的全流程突破

目录引言一、豆包新模型技术解析1.1 豆包新模型介绍1.2 核心能力突破1.2.1 情感交互能力1.2.2 推理与编码能力二、PromptPilot工具深度测评2.1 PromptPilot介绍2.2 工具架构与核心功能2.3 一个案例讲通&#xff1a;市场调研报告2.3.1 生成Prompt2.3.2 批量集生成2.3.3 模拟数据…

【代码随想录day 12】 力扣 144.145.94.前序遍历中序遍历后序遍历

视频讲解&#xff1a;https://www.bilibili.com/video/BV1Wh411S7xt/?vd_sourcea935eaede74a204ec74fd041b917810c 文档讲解&#xff1a;https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html#%E5%85%B6%E4%BB%96%E8%A…

【Unity】 HTFramework框架(六十七)UDateTime可序列化日期时间(附日期拾取器)

更新日期&#xff1a;2025年8月6日。 Github 仓库&#xff1a;https://github.com/SaiTingHu/HTFramework Gitee 仓库&#xff1a;https://gitee.com/SaiTingHu/HTFramework 索引一、UDateTime可序列化日期时间1.定义UDateTime字段2.日期拾取器&#xff08;编辑器&#xff09;3…

Docker的安装,服务器与客户端之间的通信

目录 1、Docker安装 1.1主机配置 1.2apt源的修改 1.3apt安装 2、客户端与服务端通信 2.1服务端配置 2.1.1创建镜像存放目录 2.1.2修改配置文件 2.2端口通信 2.3SSH连接 2.3.1生成密钥 2.3.2传输密钥 2.3.3测试连接 1、Docker安装 1.1主机配置 我使用的两台主机是…

【算法专题训练】09、累加子数组之和

1、题目&#xff1a;LCR 010. 和为 K 的子数组 https://leetcode.cn/problems/QTMn0o/description/ 给定一个整数数组和一个整数 k &#xff0c;请找到该数组中和为 k 的连续子数组的个数。示例 1&#xff1a; 输入:nums [1,1,1], k 2 输出: 2 解释: 此题 [1,1] 与 [1,1] 为两…

WinXP配置一键还原的方法

使用系统自带的系统还原功能&#xff1a;启用系统还原&#xff1a;右键点击 “我的电脑”&#xff0c;选择 “属性”&#xff0c;切换到 “系统还原” 选项卡&#xff0c;确保 “在所有驱动器上关闭系统还原” 未被勾选&#xff0c;并为系统驱动器&#xff08;C:&#xff09;设…

基于模式识别的订单簿大单自动化处理系统

一、系统概述 在金融交易领域&#xff0c;订单簿承载着海量的交易信息&#xff0c;其中大单的处理对于市场流动性和价格稳定性有着关键影响。基于模式识别的订单簿大单自动化处理系统旨在通过智能算法&#xff0c;精准识别订单簿中的大单特征&#xff0c;并实现自动化的高效处理…

table行内--图片预览--image

需求&#xff1a;点击预览&#xff0c;进行预览。支持多张图切换思路&#xff1a;使用插槽&#xff1b;src : 展示第一张图&#xff1b;添加preview-src-list ,用于点击预览。使用插槽&#xff08;UI组件--> avue&#xff09;column: 测试数据

560. 和为 K 的子数组 - 前缀和思想

560. 和为 K 的子数组 - 前缀和思想 在算法题中&#xff0c;前缀和是一种能快速计算 “数组中某段连续元素之和” 的预处理方法&#xff0c;核心思路是 “提前计算并存储中间结果&#xff0c;避免重复计算” 前缀和的定义&#xff1a; 对于一个数组 nums&#xff0c;我们可以创…

Python金融分析:从基础到量化交易的完整指南

Python金融分析:从基础到量化交易的完整指南 引言:Python在金融领域的核心地位 在量化投资规模突破5万亿美元的2025年,Python已成为金融分析的核心工具: 数据处理效率:Pandas处理百万行金融数据仅需2.3秒 策略回测速度:Backtrader框架使策略验证效率提升17倍 风险评估精…

MySQL 从入门到实战:全方位指南(附 Java 操作示例)

MySQL 入门全方位指南&#xff08;附Java操作示例&#xff09; MySQL 作为最流行的关系型数据库之一&#xff0c;广泛应用于各类应用开发中。本文将从安装开始&#xff0c;逐步讲解 MySQL 的核心知识点与操作技巧&#xff0c;并通过 Java 示例展示客户端交互&#xff0c;帮助你…

从低空感知迈向智能协同网络:构建智能空域的“视频基础设施”

✳️ 引言&#xff1a;低空经济起飞&#xff0c;智能视觉链路成刚需基建 随着政策逐步开放与技术加速成熟&#xff0c;低空经济正从概念走向全面起飞。从载人 eVTOL 到物流无人机&#xff0c;从空中巡检机器人到城市立体交通调度平台&#xff0c;低空场景正在成为继地面交通和…

Node.js- express的基本使用

Express 核心概念​ Express是基于Node.js的轻量级Web框架&#xff0c;封装了HTTP服务、路由管理、中间件等核心功能&#xff0c;简化了Web应用和API开发 核心优势​​ 中间件架构&#xff1a;支持模块化请求处理流程路由系统&#xff1a;直观的URL到处理函数的映射高性能&…

计算机网络:网络号和网络地址的区别

在计算机网络中&#xff0c;“网络号”和“网络地址”是两个密切相关但含义不同的概念&#xff0c;主要用于IP地址的划分和网络标识。以下从定义、作用、关联与区别等方面详细说明&#xff1a; 1. 网络号&#xff08;Network Number&#xff09;定义&#xff1a;网络号是IP地址…

【iOS】3GShare仿写

【iOS】3GShare仿写 文章目录【iOS】3GShare仿写登陆注册界面主页搜索文章活动我的总结登陆注册界面 这个界面的ui东西不多&#xff0c;主要就是几个输入框及对输入内容的一些判断 登陆界面 //这里设置了一个初始密码并储存到NSUserDefaults中 NSUserDefaults *defaults [N…

从案例学习cuda编程——线程模型和显存模型

1. cuda介绍CUDA&#xff08;Compute Unified Device Architecture&#xff0c;统一计算设备架构&#xff09;是NVIDIA推出的一种并行计算平台和编程模型。它允许开发者利用NVIDIA GPU的强大计算能力来加速计算密集型任务。CUDA通过提供一套专门的API和编程接口&#xff0c;使得…