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 作用域

声明语句的作用域是指源代码中可以有效使用这个名字的范围。
不要将作用域和生命周期混淆。生命周期是程序运行时变量存在的有效时间段,在此时间区域内他可以被程序的其他部分引用,是一个运行时的概念。
句法块
词法块
语法块
要特别注意短变量声明语句的作用域范围。

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

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

相关文章

【iOS】多界面传值

文章目录 前言一、属性传值二、协议传值三、block传值四、KVO传值五、KVO的自动触发与手动触发六、通知传值总结 前言 在写网易云音乐以及3GShare包括后面的学生管理系统时&#xff0c;用到许多界面传值方法&#xff0c;特撰写博客记录目前学过的几种多界面传值方法 一、属性…

【Docker】Docker部署私有仓库的配置及应用

文章目录 一、Docker-registry 搭建本地私有仓库1. Registry 的概念2. Registry 的部署过程 二、Docker-harbor 搭建私有仓库1. 什么是Harbor2. Harbor 的特性3. Harbor的构成4. Harbor 的部署过程4.1 安装 harbor4.2 创建项目并进行上传下载4.3 上传镜像到私有仓库4.4 从私有仓…

Vue--插槽

一、插槽-默认插槽 1.作用 让组件内部的一些 结构 支持 自定义 2.需求 将需要多次显示的对话框,封装成一个组件 3.问题 组件的内容部分&#xff0c;不希望写死&#xff0c;希望能使用的时候自定义。怎么办 4.插槽的基本语法 组件内需要定制的结构部分&#xff0c;改用**…

mysql的主键选择

一.没有定义主键有什么问题 如果定义了主键&#xff0c;那么InnoDB会使用主键作为聚簇索引如果没有定义主键&#xff0c;那么会使用第一非空的唯一索引&#xff08;NOT NULL and UNIQUE INDEX&#xff09;作为聚簇索引如果既没有主键也找不到合适的非空索引&#xff0c;那么In…

【数据挖掘】时间序列的傅里叶变换:用numpy解释的快速卷积

一、说明 本篇告诉大家一个高级数学模型&#xff0c;即傅里叶模型的使用&#xff1b; 当今&#xff0c;傅里叶变换及其所有变体构成了我们现代世界的基础&#xff0c;为压缩、通信、图像处理等技术提供了动力。我们从根源上理解&#xff0c;从根本上应用&#xff0c;这是值得付…

STM32MP157驱动开发——按键驱动(线程化处理)

文章目录 “线程化处理”机制&#xff1a;内核函数线程化处理方式的按键驱动程序(stm32mp157)编程思路button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “线程化处理”机制&#xff1a; 工作队列是在内核的线程的上下文中执行的 工作队列中有多个 work&#xff0…

Git远程仓库使用方法

目录 介绍 详细教程 1、创建远程仓库 2、在本地初始化仓库 3、关联远程仓库 4、提交代码 5、拉取到本地仓库 6、提交到Git仓库 5、将本地代码推送到远程仓库 介绍 远程仓库在协同开发中起着关键的作用&#xff0c;它提供了一个中央存储库&#xff0c;使多个开发者能够…

Hadoop中HDFS的架构

一、Switch语句 语法规则&#xff1a; ①语句中的变量类型可以是byte、short、int或者char;从javaSE5开始支持枚举类型&#xff1b; javaSE7开始&#xff0c;switch支持String。 ②没有break时&#xff0c;后续case的语句都会执行 二、修饰符 访问修饰符 Java中&#xff0c…

【C++】vector类的模拟实现(增删查改,拷贝构造,赋值运算,深浅拷贝)

文章目录 前言一、 整体1.命名空间:2构造函数&#xff1a;1普通构造2迭代器构造3初始化字符构造4拷贝构造&#xff1a; 3析构函数 二、成员函数实现1.大小1当前大小(size())2总体容量(capacity()) 2.返回头尾迭代器1begin&#xff08;&#xff09;2end&#xff08;&#xff09;…

小程序如何修改商品

​商家可能会遇到需要修改产品信息的情况。无论是价格调整、库存更新还是商品描述的修改&#xff0c;小程序提供了简便的方式来帮助你们完成这些操作。下面是一些简单的步骤和注意事项&#xff0c;帮助你们顺利地修改商品。 一、进入商品管理页面 在个人中心点击管理入口&…

面向对象编程:从抽象到直观的探索之旅

文章目录 1. 面向过程与面向对象2. 面向对象的思想3. 类与对象的关系4. 类中包含什么&#xff1f;5. 类与对象的关系结语 在编程的世界里&#xff0c;我们常常会遇到两种不同的编程思想&#xff1a;面向过程和面向对象。面向过程是一种直观且容易理解的编程方式&#xff0c;而面…

矿井人员视频行为分析算法 opencv

矿井人员视频行为分析算法通过opencvpython网络模型技术&#xff0c;矿井人员视频行为分析算法实时监测人员的作业行为&#xff0c;并与安全标准进行比对&#xff0c;可以及时发现不符合安全要求的行为&#xff0c;预防事故的发生。OpenCV的全称是Open Source Computer Vision …

教师ChatGPT的23种用法

火爆全网的ChatGPT&#xff0c;作为教师应该如何正确使用&#xff1f;本文梳理了教师ChatGPT的23种用法&#xff0c;一起来看看吧&#xff01; 1、回答问题 ChatGPT可用于实时回答问题&#xff0c;使其成为需要快速获取信息的学生的有用工具。 从这个意义上说&#xff0c;Cha…

【N32L40X】学习笔记10-外部触发方式计数

定时器采用外部触发方式计数 也就是外部时钟源模式2 此模式由 TIMx_SMCTRL .EXCEN 选择等于 1。计数器可以在外部触发输入 ETR 的每个上升沿或下降沿 计数。 极性选择分频选择过滤选择选择外部时钟ETR模式 bsp_time_counter_ETR.h #ifndef _BSP_TIME_COUNTER_ETR_H_ #defi…

CSS布局之网格布局

网格布局&#xff08;Grid Layout&#xff09;是一种CSS布局模型&#xff0c;通过将页面划分为行和列的网格&#xff0c;可以更轻松地实现复杂的布局。 要使用网格布局&#xff0c;需要将元素的display属性设置为grid。然后&#xff0c;可以使用grid-template-rows和grid-temp…

一个月学通Python(二十五):使用缓存

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍使用缓存Django项目接入Redis为视图提供缓…

AI数字人:金融数字化转型的“关键先生”

今年年初ChatGPT的火热&#xff0c;在全球掀起一阵生成式AI&#xff08;AIGC&#xff09;热潮。国外的OpenAI、国内的百度等企业&#xff0c;都在AIGC上强力布局。 各种应用场景中&#xff0c;AIGC助力的数字人引起了市场注意。 事实上&#xff0c;数字人不是个新鲜事。早在1…

在Ubuntu 系统下开发GUI,用哪种开发工具比较好?

在Ubuntu系统下开发GUI&#xff0c;你可以考虑使用以下几种开发工具&#xff1a;Qt Creator&#xff1a;Qt Creator是一个跨平台的集成开发环境&#xff0c;专门用于开发基于Qt框架的应用程序。它提供了丰富的图形界面设计工具和代码编辑器&#xff0c;支持C和QML编程。Qt Crea…

UNI-APP_横屏切换竖屏出现样式混乱问题

app从竖屏页面1进入竖屏页面2&#xff0c;再进入横屏&#xff0c;再返回&#xff0c;再返回从新回到竖屏页面1&#xff0c;再次进入竖屏页面2&#xff0c;发现竖屏页面2的所有图片字体都被放大了。再返回竖屏1&#xff0c;再进入竖屏2&#xff0c;一切又恢复正常。 解决跳转横…

[NOI2008] 设计路线

题目描述 Z 国坐落于遥远而又神奇的东方半岛上&#xff0c;在小 Z 的统治时代公路成为这里主 要的交通手段。Z 国共有 n 座城市&#xff0c;一些城市之间由双向的公路所连接。非常神 奇的是 Z 国的每个城市所处的经度都不相同&#xff0c;并且最多只和一个位于它东边的 城市直…