当前位置: 首页 > news >正文

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

和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
}

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

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

相关文章:

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

和Python、Ruby等动态脚本语言不同&#xff0c;Go语言沿袭了静态编译型语言的传统&#xff1a;使用变量之前需要先进行变量的声明。 变量声明形式使用决策流程图 这里大致列一下Go语言常见的变量声明形式&#xff1a; var a int32 var s string "hello" var i 13 …...

高可用Kuberbetes部署Prometheus + Grafana

概述 阅读官方文档部署部署Prometheus Grafana GitHub - prometheus-operator/kube-prometheus at release-0.10 环境 步骤 下周官方github仓库 git clone https://github.com/prometheus-operator/kube-prometheus.git git checkout release-0.10 进入工作目录 cd kube…...

ardupilot 安装gcc-arm-none-eabi编译工具

目录 文章目录 目录摘要0简介1.下载网站2.安装摘要 本节主要记录ardupilot使用的编译器安装过程。 0简介 gcc-arm-none-eabi是GNU项目下的软件,是一个面向裸机arm的编译器。那么说了这么多介绍,它都包含什么具体功能又怎么安装与使用呢,我们继续。 1.下载网站 gcc-arm-n…...

ORACLE集群管理-19C RAC重新配置IPV6

1 问题概述 数据库已经配置和IPV6和 IPV4双线协议&#xff0c;需要重新配置IPV6 2 关闭相关资源 1 root用户执行 ./srvctl stop scan_listener -i 1 ./srvctl stop scan ./srvctl stop listener -n orcldb1 ./srvctl stop listener -n orcldb2 ./srvctl stop vip -n orcldb…...

Mybatis实体类属性与数据库字段的对应关系

方法一:起别名 select t_id(数据库字段) tId(类的属性), ... , ...from 表名 方法二:开启驼峰映射 <!-- 开启驼峰映射 数据库 s_id java类 sId--><setting name"mapUnderscoreToCamelCase" value"true"/> 当java类中属性命名…...

Unity(三) Shader着色器初探

学习3D开发技术的时候无可避免的要接触到Shader&#xff0c;那么Shader是个什么概念呢&#xff1f;其实对于开发同事来说还是比较难理解的&#xff0c;一般来说Shader是服务于图形渲染的一类技术&#xff0c;开发人员可以通过其shader语言来自定义显卡渲染页面的算法&#xff0…...

苹果电脑要安装杀毒软件吗?mac用什么杀毒软件好?

对于这个问题让人很是纠结&#xff0c;Mac不需要杀毒这个理论一直都深入人心&#xff0c;Mac OS X权限管理特性可以防毒的说法也一直甚嚣尘上&#xff0c;很多小伙伴如我一样搞不清楚到底要不要安装杀毒软件。&#xff0c;毕竟当前个人信息安全泄露泛滥不穷的年代&#xff0c;我…...

MySQL——索引

索引在 MySQL 数据库中分三类&#xff1a; B 树索引Hash 索引全文索引 目的&#xff1a;在查询的时候提升效率 b树 参考&#xff1a;https://blog.csdn.net/qq_40649503/article/details/115799935 数据库索引&#xff0c;是数据库管理系统中一个排序的数据结构&#xf…...

110. 平衡二叉树

题目链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 递归法&#xff1a; 我的代码&#xff1a; *** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* Tree…...

遗忘因子递推最小二乘参数估计(FFRLS)

基于遗忘因子的最小二乘法电池参数辨识 最小二乘法是系统辨识中最常用的一种估算方法。为了克服最小二乘法存在”数据饱和”的问题&#xff0c;我们通常采用含有遗忘因子的递推最小二乘法(Forgetting Factor Recursive Least Square,FFRLS)算法进行电池模型的参数辨识。 1、二…...

【redis进阶】基础知识简要回顾

1. 常见功能介绍 聚合统计 使用list集合的差集、并集来统计 排序统计 SortedSet&#xff08;ZSet&#xff09;统计&#xff0c;再利用分页列出权重高的元素 二值状态统计 BitMap存储&#xff0c;获取并统计 SETBIT uid:sign:3000:202008 2 1 GETBIT uid:sign:3000:202008 2…...

HTML5-3-表格

文章目录 属性边框属性标题跨行和跨列单元格边距 HTML 表格由 <table> 标签来定义。 tr&#xff1a;tr 是 table row 的缩写&#xff0c;表示表格的一行。td&#xff1a;td 是 table data 的缩写&#xff0c;表示表格的数据单元格。th&#xff1a;th 是 table header的缩…...

Spring Boot + Vue的前后端项目结构及联调查询

Spring Boot Vue的前后端项目结构及联调查询 当你刚开始学习前后端开发时&#xff0c;可能会感到有些困惑和不知所措。下面是一些建议&#xff0c;希望能为你的学习之旅提供一些启示&#xff1a; 建立坚实的基础知识&#xff1a;学习前后端开发的第一步是建立坚实的基础知识。…...

Transformer貌似也是可以使用state递归解码和训练的

import paddle import numpy as npclass HeadLoss(paddle.nn.Layer):def __init__(self):super(HeadLoss, self).__init__()...

振弦采集仪应用地铁隧道安全监测详细解决方案

振弦采集仪应用地铁隧道安全监测详细解决方案 随着城市化进程的不断加快&#xff0c;地铁作为一种高效、便捷、环保的交通方式已经成为现代城市不可或缺的一部分。因此&#xff0c;对地铁的安全性也越来越重视&#xff0c;一般二三线以上的城市在不断发展中&#xff0c;地铁做…...

2023 IntelliJ IDEA下载、安装教程, 附详细图解

文章目录 下载与安装IDEA推荐阅读 下载与安装IDEA 首先先到官网下载最新版的IntelliJ IDEA, 下载后傻瓜式安装就好了 官网下载地址&#xff1a;https://www.jetbrains.com/ 1、下载完后在本地找到该文件&#xff0c;双击运行 idea 安装程序 2、点击 Next 3、选择安装路径&…...

波卡生态重要动态一览:w3ndi 推出,首尔、新加坡、里斯本活动接踵而至

Web3 市场冷却&#xff0c;但新的社区合作与推进仍在发生&#xff0c;技术和产品依然不断迭代。OneBlock 为你介绍波卡生态近期值得你关注的动态&#xff0c;以及接下来重要的行业活动。 波卡生态重要进展 1、最新 Referendum#110&#xff0c;提议对验证器配置进行多项修改&a…...

成都瀚网科技有限公司:抖音商家怎么免费入驻?

随着抖音成为全球最受欢迎的短视频平台之一&#xff0c;越来越多的商家开始关注抖音上的商机。抖音商家的进驻可以帮助商家扩大品牌影响力和销售渠道。那么&#xff0c;如何免费进入抖音成为商家呢&#xff1f;下面就为大家介绍一下具体步骤。 1、抖音商家如何免费注册&#xf…...

vue Router从入门到精通

文章目录 介绍使用多级路由实例 路由的query参数传递参数接收参数实例 命名路由作用使用 params参数声明接收params参数传参接收参数实例 props配置实例 router-link的replace属性编程式路由导航作用使用实例 缓存路由组件两个新的生命周期钩子实例 路由守卫作用分类全局守卫独…...

【100天精通Python】Day56:Python 数据分析_Pandas数据清洗和处理(删除填充插值,数据类型转换,去重,连接与合并)

目录 数据清洗和处理 1.处理缺失值 1.1 删除缺失值&#xff1a; 1.2 填充缺失值&#xff1a; 1.3 插值&#xff1a; 2 数据类型转换 2.1 数据类型转换 2.2 日期和时间的转换&#xff1a; 2.3 分类数据的转换&#xff1a; 2.4 自定义数据类型的转换&#xff1a; 3 数…...

phpstudy本地快速搭建网站,并外网访问【无公网IP】

文章目录 使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2.2 映…...

WebSocket的那些事(5-Spring STOMP支持之连接外部消息代理)

目录 一、序言二、开启RabbitMQ外部消息代理三、代码示例1、Maven依赖项2、相关实体3、自定义用户认证拦截器4、Websocket外部消息代理配置5、ChatController6、前端页面chat.html 四、测试示例1、群聊、私聊、后台定时推送测试2、登录RabbitMQ控制台查看队列信息 五、结语 一、…...

【数据结构】单链表详解

当我们学完顺序表的时候&#xff0c;我们发现了好多问题如下&#xff1a; 中间/头部的插入删除&#xff0c;时间复杂度为O(N)增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。例如当…...

dql的执行顺序

在 SQL 查询语言中&#xff0c;DQL&#xff08;Data Query Language&#xff09;是用于从数据库中检索数据的部分。SQL 查询的执行顺序通常按照以下步骤进行&#xff1a; FROM 子句&#xff1a;查询首先确定要从哪些表中检索数据。在 FROM 子句中列出的表格被称为源表&#xff…...

java的动态代理如何实现

一. JdkProxy jdkproxy动态代理必须基于接口(interface)实现 接口UserInterface.java public interface UserService {String getUserName(String userCde); }原始实现类&#xff1a;UseServiceImpl.java public class UserServiceImpl implements UserSerice {Overridepub…...

Java--日志管理

日志管理 作用&#xff1a; 设置日志级别&#xff0c;决定什么日志信息应该被输出、什么日志信息应该被忽略。 基本工具 见的日志管理用具有:JDK logging&#xff08;配置文件&#xff1a;logging.properties&#xff09; 和log4j(配置文件&#xff1a;log4j.properties) 。…...

Pygame中Sprite类的使用2

4 让僵尸动起来 让僵尸能够动起来&#xff0c;也就是让僵尸从屏幕右边走到屏幕左边&#xff0c;此时只需要使用while循环&#xff0c;改变僵尸图片的x轴坐标即可&#xff0c;代码如下所示。 while True:screen.fill((255,255,255))z1.rect.x - 5z1.draw(screen)z1.update()if…...

排队时延与流量强度

流量强度 设R为传输速率&#xff0c;a表示分组到达队列的平均速率&#xff0c;假定所有分组都是由L比特组成的&#xff0c;则比特到达队列的平均速率为La。比率 L a R \frac{La}{R} RLa​被成为流量强度。 根据流量强度的定义&#xff0c;我们可以很直观的得出以下结论&#x…...

mysql:如何设计互相关注业务场景

目录 业务场景 业务问题&#xff1a; 数据库表设计&#xff1a; like&#xff08;关注表&#xff09;&#xff1a; friend&#xff08;朋友表&#xff09; 并发场景下&#xff0c;SQL语句执行逻辑 比较 A 和 B 的大小&#xff0c;如果 A执行下面的逻辑&#xff1a;<&…...

AI伦理:科技发展中的人性之声

文章目录 AI伦理的关键问题1. 隐私问题2. 公平性问题3. 自主性问题4. 伦理教育问题 隐私问题的拓展分析数据收集和滥用隐私泄露和数据安全 公平性问题的拓展分析历史偏见和算法模型可解释性 自主性问题的拓展分析自主AI决策伦理框架 伦理教育的拓展分析伦理培训 结论 &#x1f…...

徐州做网站费用/湖南网络优化

一&#xff0c;bind的安装二&#xff0c;检查bind-chroot的状态&#xff0c;如果启用&#xff0c;则使用命令“bind-chroot-admin -d” 关闭三&#xff0c;主配置文件named.conf是需要手动创建的&#xff0c;可以复制生成#cp /usr/share/doc/bind-9.3.3/sample/etc/named.conf …...

不花钱的网站怎么做/济南网站建设哪家好

点击率&#xff1a;每秒钟客户端向服务器端发起的http请求个数&#xff08;不是片面的指鼠标点击次数&#xff0c;例如&#xff0c;点击一个按钮服务器返回一个页面且包含3个图片&#xff0c;那么向服务器发送的请求数为4&#xff09; 吞吐量&#xff1a;累计时间内的全部数据量…...

医疗网络营销方式/seo全网营销的方式

转载地址&#xff1a;http://blog.csdn.net/hmg25/article/details/6447067 最近在做个东西&#xff0c;巧合碰到了sharedUserId的问题&#xff0c;所以收集了一些资料&#xff0c;存存档备份。 安装在设备中的每一个apk文件&#xff0c;Android给每个APK进程分配一个单独的用户…...

免费微网站哪个好用/关键词首页排名优化平台

这是一个能够获取到用户访问信息的PHP类&#xff0c;包括&#xff1a;ip地址、地理信息、操作系统、语言、浏览器和isp等等。获取地理位置和ISP信息是请求的Baidu隐藏接口。/*** 获取访客信息的类&#xff1a;语言、浏览器、操作系统、IP、地理位置、ISP。* 日期&#xff1a;20…...

个人网站主页建设教程/做一个网站

1 引言 上一篇博文详细总结了Python进程的用法&#xff0c;这一篇博文来所以说Python中线程的用法。实际上&#xff0c;程序的运行都是以线程为基本单位的&#xff0c;每一个进程中都至少有一个线程&#xff08;主线程&#xff09;&#xff0c;线程又可以创建子线程。线程间共享…...

百度网站权重/seo营销外包

vue cnpm run dev 报错&#xff0c;解决方法参考文章&#xff1a; &#xff08;1&#xff09;vue cnpm run dev 报错&#xff0c;解决方法 &#xff08;2&#xff09;https://www.cnblogs.com/futai/p/7111950.html 备忘一下。...