Go学习 2、程序结构
2、程序结构
2.1 命名
一个名字必须以一个字母或下划线开头,后面可以跟任意数量的字母、数字或下划线。
大写字母和小写字母是不同的。
GO语言有25个关键字,关键字不能用于自定义名字。
还有大约30多个预定义名字,对应内建的常量、类型和函数,内部预定义名字可以在定义中重新使用他们,但也要避免过度而引起语义混乱。
名字是大写字母开头(必须是在函数外部定义的包级名字;包级函数名本身也是包级名字),那么它将是导出的,可以被外部的包访问。
包本身的名字一般都是用小写字母。
名字的长度没有逻辑限制,但尽量使用短小的名字。
驼峰式命名
2.2 声明
声明语句定义了程序的各种实体对象以及部分或全部的属性。
var变量、const常量、type类型、func函数实体对象
一个go语言编写的程序对应一个或多个以.go为文件后缀名的源文件中。每个源文件以包的声明语句开始(说明该源文件是属于哪个包),包声明语句之后是import语句导入依赖的其他包,然后是包一级的类型、变量、常量、函数的声明语句(包一级的各种类型的声明语句的顺序无光紧要,函数内部的名字则必须先声明之后才能使用)
package mainimport "fmt"const boilingF=212.0func main(){var f=boilingFvar c=(f-32)*5/9fmt.Printf("boiling point=%g F or %g C\n",f,c)
}
在包一级声明语句的名字可在整个包对应的每个源文件中访问,而不仅仅在其声明语句所在的源文件中访问,局部声明的名字就只能在函数内部很小的范围被访问。
package mainimport "fmt"func main(){const freezingF,boilingF=32.0 212.0fmt.Printf("%g F or %g C\n",freezingF,fToC(freezingF))fmt.Printf("%g F or %g C\n",boilingF,fToC(boilingF))
}func fToC(f float64) float64{return (f-32)*5/9
}
2.3 变量
var 变量名字 类型=表达式
零值初始化机制
var s string
fmt.Println(s)//""
一组变量
var i,j,k int
var b,f,s=true,2.3,"four"
在包级别声明的变量会在main入口函数执行前完成初始化,局部变量将在声明语句被执行到的时候完成初始化。
一组变量也可以通过调用一个函数,由函数返回的多个返回值初始化
var f,err=os.Open(name)
2.3.1 简短变量声明
变量的类型根据表达式来自动推导,简短变量声明被广泛用于大部分的局部变量的声明和初始化。
变量名:=表达式
i:=100
j,k:=0,1
f,err:=os.Open(name)
简短变量声明左边的变量可能并不是全部都是刚刚声明过。如果有一些已经在相同的词法域声明过了,那么简短变量声明语句对这些已经声明过的变量就只有赋值行为了。
in,err:=os.Open(infile)
out,err:=os.Create(outfile)
简短变量语句中必须至少要声明一个新的变量。
简短变量声明语句只有对已经在同级词法域声明过的变量才和赋值操作语句等价,如果变量是在外部词法域声明的,那么简短变量声明语句将会在当前词法域重新声明一个新的变量。
2.3.2 指针
指针的值是另一个变量的地址。
& x//取变量x的内存地址
*p//读取指针指向的变量的值
x:=1
p:=&x
fmt.Println(*p)//1
*p=2
fmt.Println(x)//2
var x,y int
fmt.Println(&x==&x,&x==&y,&x==nil)//true false false
返回函数中局部变量的地址也是安全的。
var p=f()func f() *int{v:=1return &v
}
每次调用f函数都将返回不同的结果:
fmt.Println(f()==f())//false
指针作为参数调用函数,可以在函数中通过该指针来更新变量的值。
func incr(p *int) int{*p++//增加p指向的变量的值,并不改变p指针return *p
}v:=1
incr(&v)//2
fmt.Println(incr(&v))//3
*p是变量v的别名
指针是实现标准库flag包的关键技术,它使用命令行参数来设置对应变量的值,而这些对应命令行标志参数的变量可能会零散分布在整个程序中。
2.3.3 new函数
创建变量
new(T)将创建一个T类型的匿名变量,初始化为T类型的零值,然后返回变量地址,返回的指针类型为*T
p:=new(int)//p,*int 类型,指向匿名的int变量
fmt.Println(*p)//0
*p=2
fmt.Println(*p)//2
用new创建变量和普通变量声明语句方式创建变量没有什么区别,除了不需要声明一个临时变量的名字。
在表达式中使用new(T)
下面的两个newInt函数有着相同的行为
func newInt() *int{return new(int)
}func newInt() *int{var dummy intreturn &dummy
}
每次调用new函数都是返回一个新的变量地址,下面两个地址都是不同的:
p:=new(int)
q:=new(int)
fmt.Println(p==q)//false
new只是一个预定义函数,它并不是一个关键字,我们可以将new名字重新定义别的类型
func delta(old,new int) int {return new-old}
由于new被定义为int类型的变量名,因此delta函数内部是无法使用内置的new函数的。
2.3.4 变量的生命周期
包一级声明的变量,生命周期和整个程序的运行周期是一致的。
局部变量的声明周期则是动态的:每次从创建一个新变量的声明语句开始,直到该变量不再被引用为止,然后变量的存储空间可能被回收。函数的参数变量和返回值变量都是局部变量。它们在函数每次被调用的时候创建。
函数的右小括弧也可以另起一行缩进,同时为了防止编译器在行尾自动插入分号而导致编译错误,可以在末尾的参数变量后面显式插入逗号。
img.SetColorIndex(size+int(x*size+0.5),size+int(y*size+0.5),blackIndex,
)
Go语言的==自动垃圾收集器【不需要显式地分配和释放内存】==是如何知道一个变量是何时可以被回收的?基本实现思路:从每个包级的变量和每个当前运行函数的每个当前运行函数的每一个局部变量开始,通过指针或引用的访问路径遍历,是否可以找到该变量。如果不存在这样的访问路径,那么说明该变量是不可达的,也就是说它是否存在并不影响程序后续的计算结果。
一个变量的有效周期只取决于是否可达,因此一个循环迭代内部的局部变量的生命周期可能超出其局部作用域。局部变量可能在函数返回之后依然存在。
编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,这个选择并不是由var还是new声明变量的方式决定。
var global *intfunc f(){var x intx=1global=&x
}func g(){y:=new(int)*y=1
}
f函数的x变量必须在堆上分配,它在函数退出后依然可以通过包一级的global变量找到,虽然它是在函数内部定义的(x局部变量从函数f中逃逸了)。
当g函数返回时,变量*y将是不可达的,可以马上被回收的,编译器可以选择在栈上分配存储空间。
2.4 赋值
x=1
*p=true
person.name="bob"
count[x]=count[x]*scale
count[x]*=scale
++递增和–递减语句,是语句而不是表达式x=i++是错误的
v:=1
v++
v--
2.4.1 元组赋值
同时更新多个变量的值
x,y=y,x
a[i],a[j]=a[j],a[i]
//计算两个整数值的最大公约数
func gcd(x,y int) int{for y!=0{x,y=y,x%y}return x
}
//计算斐波纳契数列的第n个数func fib(n int)int{x,y:=0,1for i:=0;i<n;i++{x,y=y,x+y}return x
}
元组赋值可以使一系列琐碎赋值更加紧凑,特别是在for循环的初始化部分
i,j,k=2,3,5
调用一个有多个返回值的函数
f,err=os.Open("foo.txt")
如果map查找、类型断言或通信接收出现在赋值语句的右边,它们都可能会产生两个结果,有一个额外的布尔结果表示操作是否成功:
v,ok=map[key]
v,ok=x.(T)
v,ok=<-ch
map查找、类型断言或通道接收出现在赋值语句的右边,并不一定是产生两个结果,也可能只产生一个结果。map查找失败时返回零值,类型断言失败时会发送运行panic异常,通道接收失败时会返回零值(阻塞不算是失败)。
我们可以用_来丢弃不需要的值。
_,err=io.Cpoy(dst,src)//丢弃字节数
_,ok=X.(T)//只检测类型,忽略具体值
2.4.2 可赋值性
隐式赋值行为:函数调用会隐式地将调用参数的值赋值给函数的参数变量,一个返回语句会隐式地将返回操作的值赋值给结果变量,一个复合类型的字面量也会产生赋值行为。
隐式地对slice的每个元素进行赋值操作:
medals:=[]string{"gold","silver","bronze"}
类型必须完全匹配,nil可以赋值给任何指针或引用类型的变量。避免不必要的显式的类型转换。
2.5 类型
类型声明语句创建一个新的类型名称:
type 类型名字 底层类型
类型声明语句一般出现在包一级,如果新创建的类型名字的首字符大写,则在外部包也可以使用
我们将不同温度单位分别定义为不同的类型:
package tempconvimport "fmt"type Celsius float64 //摄氏温度
type Fahrenheit float64//华氏温度const (AbsoluteZeroC Celsius=-273.15//绝对零度FreezingC Celsius=0//结冰点零度BoilingC Celsius=100//沸水温度
)func CToF(c Celsius) Fahrenheit {return Fahrenheit(c*9/5+32)}func FToC(f Fahrenheit) Celsius {return Celsius((f-32)*5/9)}
对于每一个类型T,都有一个对应的类型转换操作T(x),将x转为T类型。
命名类型还可以为该类型的值定义新的行为。
声明Celsius类型的一个名为String方法。
func (c Celsius) String() string {return fmt.Sprintf("%g C",c)}
2.6 包和文件
包:为了支持模块化、封装、单独编译和代码重用。
2.6.1 导入包
每个包都有一个全局唯一的导入路径。
包名在包的声明处指定。
import 包名
如果导入了一个包,但是又没有使用该包将当作一个编译错误处理。
goimports工具,根据需要自动添加或删除导入的包。
2.6.2 包的初始化
包的初始化首先是解决包级变量的依赖顺序,然后按照包级变量声明出现的顺序依次初始化。
var a=b+c //3
var b=f() //2
var c=1 //1
func f() int {return c+1}
如果包中含有多个.go源文件,它们将按照发给编译器的顺序进行初始化
初始化表达式初始化,特殊的init初始化函数来简化初始化工作
每个包在解决依赖的前提下,以导入声明的顺序初始化,每个包只会被初始化一次。
匿名函数
2.7 作用域
声明语句的作用域是指源代码中可以有效使用这个名字的范围。
不要将作用域和生命周期混淆。生命周期是程序运行时变量存在的有效时间段,在此时间区域内他可以被程序的其他部分引用,是一个运行时的概念。
句法块
词法块
语法块
要特别注意短变量声明语句的作用域范围。
相关文章:
Go学习 2、程序结构
2、程序结构 2.1 命名 一个名字必须以一个字母或下划线开头,后面可以跟任意数量的字母、数字或下划线。 大写字母和小写字母是不同的。 GO语言有25个关键字,关键字不能用于自定义名字。 还有大约30多个预定义名字,对应内建的常量、类型和函…...

SpringBoot整合JavaMail
SpringBoot整合JavaMail 简单使用-发送简单邮件 介绍协议 导入坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>添加配置 spring:mail:host: smtp.qq.co…...

Spring6——入门
文章目录 入门环境要求构建模块程序开发引入依赖创建java类创建配置文件创建测试类运行测试程序 程序分析启用Log4j2日志框架Log4j2日志概述引入Log4j2依赖加入日志配置文件测试使用日志 入门 环境要求 JDK:Java17(Spring6要求JDK最低版本是Java17&…...

【计算机视觉 | 目标检测 | 图像分割】arxiv 计算机视觉关于目标检测和图像分割的学术速递(7 月 17 日论文合集)
文章目录 一、检测相关(5篇)1.1 TALL: Thumbnail Layout for Deepfake Video Detection1.2 Cloud Detection in Multispectral Satellite Images Using Support Vector Machines With Quantum Kernels1.3 Multimodal Motion Conditioned Diffusion Model for Skeleton-based Vi…...

为什么需要GP(Global Platform)认证?
TEE之GP(Global Platform)认证汇总 一、为什么需要认证? 二、为什么是GP? 参考: GlobalPlatform Certification - GlobalPlatform...
eclipse 格式化代码 快捷键
在Eclipse中,可以使用以下快捷键来格式化代码: Windows/Linux快捷键:Ctrl Shift FMac快捷键:Command Shift F 按下相应的快捷键后,Eclipse将自动根据您的代码格式化偏好设置对代码进行格式化。请确保已经选择和配…...
深入探索Socks5代理与网络安全
简介 Socks5代理是一种网络协议,用于在客户端和服务器之间进行数据传输,它可以在网络层和传输层实现代理功能。与其他代理协议相比,Socks5代理更加灵活和安全,为爬虫任务和网络安全提供了重要支持。 Socks5代理的工作原理 Socks5…...

【NLP】如何使用Hugging-Face-Pipelines?
一、说明 随着最近开发的库,执行深度学习分析变得更加容易。其中一个库是拥抱脸。Hugging Face 是一个平台,可为 NLP 任务(如文本分类、情感分析等)提供预先训练的语言模型。 本博客将引导您了解如何使用拥抱面部管道执行 NLP 任务…...

网络安全(黑客)自学笔记
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一是市场需求量高; 二则是发展相对成熟入门…...
spring数据校验
数据校验 概述 在开发中,会存在参数校验的情况,如:注册时,校验用户名不能为空、用户名长度不超过20个字符,手机号格式合法等。如果使用普通方式,会将校验代码和处理逻辑耦合在一起,在需要新增一…...

因材施教,有道发布“子曰”教育大模型,落地虚拟人口语教练等六大应用
因材施教的教育宗旨下,大模型浪潮中,网易有道凭借其对教育场景的深入理解和对商业化的理性思考,为行业树立了垂直大模型的典范。 7月26日,教育科技公司网易有道举办了“powered by 子曰”教育大模型应用成果发布会。会上重磅推出了…...

golang waitgroup
案例 WaitGroup 可以解决一个 goroutine 等待多个 goroutine 同时结束的场景,这个比较常见的场景就是例如 后端 worker 启动了多个消费者干活,还有爬虫并发爬取数据,多线程下载等等。 我们这里模拟一个 worker 的例子 package mainimport (…...
单列模式多学两遍
单例模式 单例模式(Singleton Pattern,也称为单件模式),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。 定义单例类 ● 私有化它的构造函数,…...

Spring Cloud【SkyWalking网络钩子Webhooks、SkyWalking钉钉告警、SkyWalking邮件告警】(十六)
目录 分布式请求链路追踪_SkyWalking网络钩子Webhooks 分布式请求链路追踪_SkyWalking钉钉告警 分布式请求链路追踪_SkyWalking邮件告警 分布式请求链路追踪_SkyWalking网络钩子Webhooks Wbhooks网络钩子 Webhok可以简单理解为是一种Web层面的回调机制。告警就是一个事件&a…...

【力扣每日一题】2023.7.25 将数组和减半的最少操作次数
目录 题目: 示例: 分析: 代码运行结果: 题目: 示例: 分析: 题目给我们一个数组,我们每次可以将任意一个元素减半,问我们操作几次之后才可以将整个数组的和减半&…...

Docker-Compose 轻松搭建 Grafana+InfluxDb 实用 Jmeter 监控面板
目录 前言: 1、背景 2、GranfanaInfluxDB 配置 2.1 服务搭建 2.2 配置 Grafana 数据源 2.3 配置 Grafana 面板 3、Jmeter 配置 3.1 配置 InfluxDB 监听器 3.2 实际效果 前言: Grafana 和 InfluxDB 是两个非常流行的监控工具,它们可…...

异构线程池的c++实现方案
概要 通常线程池是同质的,每个线程都可以执行任意的task(每个线程中的task顺序执行),如下图所示: 但本文所介绍的线程和task之间有绑定关系,如A task只能跑在A thread上(因此称为异构线程池&am…...

Python实现抽象工厂模式
抽象工厂模式是一种创建型设计模式,用于创建一系列相关或依赖对象的家族,而无需指定具体类。在Python中,可以通过类和接口的组合来实现抽象工厂模式。 下面是一个简单的Python实现抽象工厂模式的示例: # 抽象产品接口 class Abs…...

@vue/cli安装
vue/cli安装 1、全局安装vue/cli包2、查看是否成功 1、全局安装vue/cli包 yarn global add vue/cli2、查看是否成功 vue -V...

用友全版本任意文件上传漏洞复现
声明 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 文章作者拥有对此文章的修改和解释权。如欲转载或传播此文章,…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...