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

用友全版本任意文件上传漏洞复现
声明 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 文章作者拥有对此文章的修改和解释权。如欲转载或传播此文章,…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...