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...

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

程序员面试系列,MySQL常见面试题?
原文链接 一、索引相关的面试题 (1)索引失效的情况有哪些 在MySQL查询时,以下情况可能会导致索引失效,无法使用索引进行高效的查询: 数据类型不匹配:如果查询条件中的数据类型与索引列的数据类型不匹配&…...

前端Web实战:从零打造一个类Visio的流程图拓扑图绘图工具
前言 大家好,本系列从Web前端实战的角度,给大家分享介绍如何从零打造一个自己专属的绘图工具,实现流程图、拓扑图、脑图等类Visio的绘图工具。 你将收获 免费好用、专属自己的绘图工具前端项目实战学习如何从0搭建一个前端项目等基础框架项…...

2023牛客暑期多校第二场部分题解
索引 ABCDEFGHIK A 队友开的题,说是其实就是问能不能用若干个数异或出来某个数。 应该就是线性基板子,然后他写了一下就过了。 B 一开始看没什么人过不是很敢开,结果到后面一看题——这不是最大权闭合子图板子吗??…...

20230724将真我Realme手机GT NEO3连接到WIN10的电脑的步骤
20230724将真我Realme手机GT NEO3连接到WIN10的电脑的步骤 2023/7/24 23:23 缘起:因为找使用IMX766的手机,找到Realme手机GT NEO3了。 同样使用IMX766的还有:Redmi Note12Pro 5G IMX766 旗舰影像 OIS光学防抖 OLED柔性直屏 8GB256GB时光蓝 现…...

黑马 pink h5+css3+移动端前端
网页概念 网页是网站的一页,网页有很多元素组成,包括视频图片文字视频链接等等,以.htm和.html后缀结尾,俗称html文件 HTML 超文本标记语言,描述网页语言,不是编程语言,是标记语言,有标签组成 超文本指的是不光文本,还有图片视频等等标签 常用浏览器 firefox google safari…...

Docker的七项优秀实践
众所周知,作为一个文本文档,Dockerfile包含了用户创建镜像的所有命令和说明。Docker可以通过读取Dockerfile中指令的方式,去自动构建镜像。因此,大家往往认为编写Dockerfile理应非常简单,只需从互联网上选择一个示例&a…...

【数据结构】24王道考研笔记——图
六、图 目录 六、图定义及基本术语图的定义有向图以及无向图简单图以及多重图度顶点-顶点间关系连通图、强连通图子图连通分量强连通分量生成树生成森林边的权、带权网/图特殊形态的图 图的存储及基本操作邻接矩阵邻接表法十字链表邻接多重表分析对比图的基本操作 图的遍历广度…...

zabbix钉钉报警
登录钉钉客户端,创建一个群,把需要收到报警信息的人员都拉到这个群内. 然后点击群右上角 的"群机器人"->"添加机器人"->"自定义", 记录该机器人的webhook值。 添加机器人 在钉钉群中,找到只能群助手 添加机器人 选择自定义机…...

Spring 源码解读
1、Spring 的结构组成 1.1、核心类介绍 Spring 中有两个最核心的类 1 DefaultListableBeanFactory XmlBeanFactory 继承自 DefaultListableBeanFactory,而DefaultListableBeanFactory 是整个 bean加载的核心部分,是 Spring 注册及加载 bean 的默认实现…...

练习时长两年半的网络安全防御“first”
1.网络安全常识及术语 下边基于这次攻击演示我们介绍一下网络安全的一些常识和术语。 资产 任何对组织业务具有价值的信息资产,包括计算机硬件、通信设施、 IT 环境、数据库、软件、文档资料、信息服务和人员等。 网络安全 网络安全是指网络系统的硬件、软件及…...