小白学go基础05-变量声明形式

news2024/12/23 13:47:01

和Python、Ruby等动态脚本语言不同,Go语言沿袭了静态编译型语言的传统:使用变量之前需要先进行变量的声明。

变量声明形式使用决策流程图

在这里插入图片描述

这里大致列一下Go语言常见的变量声明形式:

var a int32
var s string = "hello"
var i = 13
n := 17
var (
crlf = []byte("\r\n")
colonSpace = []byte(": ")
)

如果让Go语言的设计者重新设计一次变量声明语法,相信他们很大可能不会再给予Gopher这么大的变量声明灵活性,但目前这一切都无法改变。对于以面向工程著称且以解决规模化问题为目标的Go语言,Gopher在变量声明形式的选择上应尽量保持项目范围内一致。

Go语言有两类变量。

包级变量(package variable):在package级别可见的变量。如果是导出变量,则该包级变量也可以被视为全局变量。

局部变量(local variable):函数或方法体内声明的变量,仅在函数或方法体内可见。

下面来分别说明实现这两类变量在声明形式选择上保持一致性的一些最佳实践。

包级变量的声明形式

包级变量只能使用带有var关键字的变量声明形式,但在形式细节上仍有一定的灵活度。我们从声明变量时是否延迟初始化这个角度对包级变量进行一次分类。

1. 声明并同时显式初始化

下面是摘自Go标准库中的代码(Go 1.12):

// $GOROOT/src/io/pipe.go
var ErrClosedPipe = errors.New("io: read/write on closed pipe")

// $GOROOT/src/io/io.go
var EOF = errors.New("EOF")
var ErrShortWrite = errors.New("short write")

我们看到,对于在声明变量的同时进行显式初始化的这类包级变量,实践中多使用下面的格式:

var variableName = InitExpression

Go编译器会自动根据等号右侧的InitExpression表达式求值的类型确定左侧所声明变量的类型。

如果InitExpression采用的是不带有类型信息的常量表达式,比如下面的语句:

var a = 17
var f = 3.14

则包级变量会被设置为常量表达式的默认类型:以整型值初始化的变量a,Go编译器会将之设置为默认类型int;而以浮点值初始化的变量f,Go编译器会将之设置为默认类型float64。

如果不接受默认类型,而是要显式为包级变量a和f指定类型,那么有以下两种声明方式:

// 第一种
var a int32 = 17
var f float32 = 3.14
// 第二种
var a = int32(17)
var f = float32(3.14)

从声明一致性的角度出发,Go语言官方更推荐后者,这样就统一了接受默认类型和显式指定类型两种声明形式。尤其是在将这些变量放在一个var块中声明时,我们更青睐这样的形式:

var (
a = 17
f = float32(3.14)
)

而不是下面这种看起来不一致的声明形式:

var (
a = 17
f float32 = 3.14
)

2. 声明但延迟初始化

对于声明时并不显式初始化的包级变量,我们使用最基本的声明形式:

var a int32
var f float64

虽然没有显式初始化,但Go语言会让这些变量拥有初始的“零值”。如果是自定义的类型,保证其零值可用是非常必要的,这一点将在后文中详细说明。

3. 声明聚类与就近原则

Go语言提供var块用于将多个变量声明语句放在一起,并且在语法上不会限制放置在var块中的声明类型。

但是我们一般将同一类的变量声明放在一个var块中,将不同类的声
明放在不同的var块中;或者将延迟初始化的变量声明放在一个var块,而将声明并显式初始化的变量放在另一个var块中,称之为“声明聚类”。

比如下面Go标准库中的代码:

// $GOROOT/src/net/http/server.go
var (
bufioReaderPool sync.Pool
bufioWriter2kPool sync.Pool
bufioWriter4kPool sync.Pool
)
var copyBufPool = sync.Pool {
New: func() interface{} {
b := make([]byte, 32*1024)
return &b
},
}
...
// $GOROOT/src/net/net.go
var (
aLongTimeAgo = time.Unix(1, 0)
noDeadline = time.Time{}
noCancel = (chan struct{})(nil)
)
var threadLimit chan struct{}
...

我们看到在server.go中,copyBufPool变量没有被放入var块中,因为它的声明带有显式初始化,而var块中的变量声明都是延迟初始化的;

net.go中的threadLimit被单独放在var块外面,一方面是考虑它是延迟初始化的变量声明,另一方面是考虑threadLimit在含义上与var块中标识时间限制的变量有所不同。

局部变量的声明形式

1. 对于延迟初始化的局部变量声明,采用带有var关键字的声明形式

比如标准库strings包中byteReplacer的方法Replace中的变量buf:

// $GOROOT/src/strings/replace.go
func (r *byteReplacer) Replace(s string) string {
var buf []byte // 延迟分配
for i := 0; i < len(s); i++ {
b := s[i]
if r[b] != b {
if buf == nil {
buf = []byte(s)
}
buf[i] = r[b]
}
}
if buf == nil {
return s
}
return string(buf)
}

另一种常见的采用带var关键字声明形式的变量是error类型的变量err(将error类型变量实例命名为err也是Go的一个惯用法),尤其是当defer后接的闭包函数需要使用err判断函数/方法退出状态时。示例代码如下:

func Foo() {
var err error
defer func() {
if err != nil {
...
}
}()
err = Bar()
...
}

2. 对于声明且显式初始化的局部变量,建议使用短变量声明形式

短变量声明形式是局部变量最常用的声明形式,它遍布Go标准库代码。对于接受默认类型的变量,可以使用下面的形式:

a := 17
f := 3.14
s := "hello, gopher!"

3. 尽量在分支控制时应用短变量声明形式

这应该是Go中短变量声明形式应用最广泛的场景了。在编写Go代码时,我们很少单独声明在分支控制语句中使用的变量,而是通过短变量声明形式将其与if、for等融合在一起,就像下面这样:

// $GOROOT/src/net/net.go
func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
// 笔者注:在if循环控制语句中使用短变量声明形式
if wv, ok := w.(buffersWriter); ok {
return wv.writeBuffers(v)
}
// 笔者注:在for条件控制语句中使用短变量声明形式
for _, b := range *v {
nb, err := w.Write(b)
n += int64(nb)
if err != nil {
v.consume(n)
return n, err
}
}
v.consume(n)
return n, nil
}

这样的应用方式体现出“就近原则”,让变量的作用域最小化了。

想做好代码中变量声明的一致性,需要明确要声明的变量是包
级变量还是局部变量、是否要延迟初始化、是否接受默认类型、是否为分支控制变量,并结合聚类和就近原则。

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

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

相关文章

C# void 关键字学习

C#中void关键字是System.Void的别名&#xff1b; 可以将 void 用作方法&#xff08;或本地函数&#xff09;的返回类型来指定该方法不返回值&#xff1b; 如果C&#xff03;方法中没有参数&#xff0c;则不能将void用作参数&#xff1b;这是与C语言不同的&#xff0c;C语言有…

附录2-将三国演义按章节存储为不同的txt(bs4)

地址 《三国演义》全集在线阅读_史书典籍_诗词名句网 目录 1 项目分析 2 代码 1 项目分析 我们可以在首页中找到所有的章节 每一个章节是一个a标签&#xff0c;a标签连接到该章节的内容 但这个网站他有bug&#xff0c;章节都是乱套的&#xff0c;我们无视这种错误&#…

Python通过Socket操作RFID设备-盘点功能

项目介绍&#xff1a;根据这么多年的IT经验&#xff0c;需求通过与用户沟通发现的&#xff0c;机会也是这样出来的。仓库的小伙子跟我倒苦水&#xff0c;动不动实物盘点&#xff0c;几千颗物料&#xff0c;都忙疯了&#xff0c;而且&#xff0c;新的物料一入库&#xff0c;作为…

基于Matlab分析的电力系统可视化研究

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

什么是专线网络?互联网专线为什么贵

宽带主要分为专线和家庭宽带。一般来说&#xff0c;企业服务器和云服务提供商通常使用专线宽带&#xff0c;普通家庭接入家庭宽带。 什么是专线网络&#xff1f; 专线是指依托国内骨干网络和宽带城市网络资源&#xff0c;为企业集团客户提供专线接入方式互联网城市互联网&…

WebDAV之π-Disk派盘 + 无忧日记

无忧日记,生活无忧无虑。 给用户专业的手机记录工具,用户可以很轻松地通过软件进行每天发生事情的记录,可以为用户提供优质的工具与帮助,用户还可以通过软件来将地理位置,天气都记录在日记上,用户也可以通过软件来进行图片的导入,创建长图日记, 心情报表:用户写日记…

企业架构LNMP学习笔记14

默认官方模块&#xff1a; Gzip压缩&#xff1a; 压缩文件&#xff0c;使文件变小了&#xff0c;传输更快了&#xff0c;目前大部分市场浏览器都支持Gzip。 传输的时候省流量。 目的是为了提高用户的加载速度。 #开启gzip压缩 gzip on; #http协议版本 gzip_http_version 1.0…

css之层叠上下文

之前调元素的显示优先级时&#xff0c;只会默默的调z-index以达到效果&#xff0c;但有时不生效&#xff0c;又不知道根因。刚好详细了解到层叠上下文&#xff0c;可以解释此类问题。 什么是层叠上下文&#xff1f; 在CSS2.1规范中&#xff0c;每个盒模型的位置是三维的&…

智能电网时代:数字孪生的崭露头角

随着科技的不断进步&#xff0c;数字孪生已经开始在电力行业崭露头角&#xff0c;为这个关键的行业带来了前所未有的机遇和潜力。本文就带大家了解一下数字孪生在哪些方面为电力行业做出改变&#xff0c;以及未来的创新应用。 首先&#xff0c;数字孪生可以提高电力系统运营效率…

Mysql事务及锁

一、MVCC原理 1.1 版本链 trx_id &#xff1a;每次一个事务对某条聚簇索引记录进行改动时&#xff0c;都会把该事务的 事务id 赋值给 trx_id 隐藏列。 roll_pointer &#xff1a;每次对某条聚簇索引记录进行改动时&#xff0c;都会把旧的版本写入到 undo日志 中&#xff0…

木棒切割问题

题目很简单&#xff0c;就是我们在写二分的时候&#xff0c;会遇到这样的情况&#xff1a; mid left (right-left)/2; if (nums k)return mid;if (nums>k)left mid;if (nums<k)right mid-1; 若我们debug会发现其可能会一致卡在left mid&#xff0c;例如&#xff08…

ceph Monitor原理和代码流程介绍

Monitor介绍 Monitor在Ceph集群中扮演管理者的角色&#xff0c;维护了整个集群的状态&#xff0c;集群的状态被抽象成几个Map对象&#xff0c;包括monmap、osdmap、mdsmap、authmap、logmap等&#xff0c;保证集群的相关组件在同一时刻能够达成一致&#xff0c;相当于领导层。…

语言深入理解指针(非常详细)(三)

目录 数组名的理解使用指针访问数组 一维数组传参的本质二级指针指针数组指针数组模拟二维数组 数组名的理解 在上⼀个章节我们在使用指针访问数组的内容时&#xff0c;有这样的代码&#xff1a; int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0];这里我们使用 &am…

医者无疆 | AI赋能大医精诚,医疗制药的进阶与突破

在历史的长河中&#xff0c;医学一直是人类文明的重要组成部分。从古希腊的希波克拉底到现代医学研究&#xff0c;医学始终与时俱进&#xff0c;为人类的健康和福祉做出了巨大的贡献。在互联网、大数据、5G等信息技术的迭代下&#xff0c;人工智能&#xff08;AI&#xff09;的…

cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)

&#xff08;1&#xff09; unordered_map 模板有如下的模板调用和包含关系。 绿箭头1 处的模板类&#xff0c;继承了绿箭头2 &#xff0c; 绿箭头2 又继承了红框模板。但红框模板有一个泛化版本和一个特化版本&#xff0c;选择哪一个呢&#xff1f; 经过源代码查找&#xff0…

腾讯张乐:“反内卷”潮流已至,研发效能是软件企业必由之路

目录 Why&#xff5c;“狂飙”踩下刹车&#xff0c;“湖水岩石效应”加速显现 What&#xff5c;效能 ≠ 效率&#xff0c;效能 效率 有效性 How&#xff5c;研发效能“黄金三角” e.g.&#xff5c;软件研发效能实践中的“坑”与“解” 1. 忽视重视工程师的声音 2. “迷…

【Spring】SpringBoot的10个参数验证技巧

这里写目录标题 前言1.使用验证注解2 使用自定义验证注解3 在服务器端验证4 提供有意义的错误信息5 将 i18n 用于错误消息messages.properties6 使用分组验证7 对复杂逻辑使用跨域验证8 对验证错误使用异常处理9 测试你的验证逻辑10 考虑客户端验证总结 前言 参数验证很重要&am…

跨空间域数据管理分布式共识算法:现状、挑战和展望

跨空间域数据管理分布式共识算法&#xff1a;现状、挑战和展望 李伟明1&#xff0c;李彤1,2, 张大方1&#xff0c;戴隆超1,2, 柴云鹏1,2 1 中国人民大学信息学院&#xff0c;北京 100872 2 数据工程与知识工程教育部重点实验室&#xff0c;北京 100872 摘要&#xff1a;随着数字…

生信学院|09月08日《SOLIDWORKS扣合特征应用》

课程主题&#xff1a;SOLIDWORKS扣合特征应用课程时间&#xff1a;2023年09月08日 14:00-14:30主讲人&#xff1a;陈冬冬 生信科技 售后服务工程师1、什么是扣合特征2、唇缘与凹槽3、装配体凸4、台通风孔5、弹簧扣与弹簧扣卡槽请安装腾讯会议客户端或APP&#xff0c;微信扫描海…

管理类联考——数学——汇总篇——知识点突破——数据分析——计数原理——排列组合——分堆分配

⛲️ 一、考点讲解 1.方法介绍 在排列组合中&#xff0c;经常遇到元素分堆或分组问题&#xff0c;尤其难点是出现等数量的分堆&#xff0c;很多考生容易犯错误。 2.方法应用 平均分成的组&#xff0c;不管他们的顺序如何&#xff0c;都是一种情况&#xff0c;所以分组后一定要…