一起聊聊Go语言中的语法糖的使用
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《一起聊聊Go语言中的语法糖的使用》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!
进入正题
至于什么是语法糖,名词解释我就不解释了,老司机自然是懂,新手司机想了解的可以去百度问一下。闲话少说我们直接开讲。
可变长参数
Go语言允许一个函数把任意数量的值作为参数,Go语言内置了... 操作符,在函数的最后一个形参才能使用...操作符,使用它必须注意如下事项
- 可变长参数必须在函数列表的最后一个;
- 把可变长参数当
切片来解析,可变长参数没有没有值时就是个空切片 - 可变长参数的类型必须相同
func test(a int, b ...int) {
fmt.Println("a=", a, ",b=", b, ",b的类型=", reflect.TypeOf(b))
return
}
输出结果如下:
a= 1 ,b= [] ,b的类型= []int
为啥说可变长参数的值用切片来解析,而不是数组。为什么是这样有兴趣的朋友可以思考一下
可变长参数这个语法糖,不是Go独有的,Java中也有,不同的是Java是通过数组实现此语法糖的。从实际开发经验来看,这个语法糖我在使用Java开发时,貌似一次都没有用过,用Go开发的时候我用的次数还挺多的,具体在什么地方用,后面有机会我再说说它是如何使用的。
声明不定长数组
我么都知道数组长度是固定的,所以在声明数组的时候都要指定长度,Go里提供了一种偷懒的声明方式,即使用...操作符声明数组时,我们只管填充元素值,其他的由Go编译器来处理。
// Go的实现:数组长度是4,等同于 a := [4]{1, 2, 3, 4}
a := [...]int{1, 2, 3, 4}
这个Java中有实现,而且感觉比Go的还简单,具体如下:
// Java的实现:数组长度是4
int[] x = {1,2,3,4};
在我短暂的职业生涯中,无论我使用Java还是Go开发的时候,数组使用的频率都是比较少的。
ps 我发现这个...好像也算是一个语法糖
... 操作符
...这个叫啥名字,我也没有找到官方的叫法。但是我发现在Go实际的开发过程中用的地方还蛮多的。
- 函数的参数声明。 如:
func funcName(nums ...int),在函数的方法体内,nums作为一个切片[]int来使用,这个上面已经提到了。 - 传参时列表打散。 如:
params = []int{1,2,3},调用某个有三个参数的方法func ThreeParamFunc(a, b, c int)时可以ThreeParamFunc(params...)。三个点...在JavaScript中的名叫扩展运算符,是在ES6中新增加的内容,它可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造字面量对象时将对象表达式按照key-value的方式展开,例如:
// 数组
var number = [1,2,3,4,5,6]
console.log(...number) //1 2 3 4 5 6
//对象
var man = {name:'蔡',height:180}
console.log({...man}) / {name:'蔡',height:180}
所以我觉得在Go里面在这种情况下,我们也可以称...为扩展运算符。
- 声明不定长数组。 如果元素指定,那么可以不必显式声明数组长度,可以根据元素个数推断,如:
arr := [...]int{1,2,3},这个上面已经提到了。 - 在 go 命令行中,被当做包列表的通配符。如:
$ go test ./...这条命令会执行当前目录及子目录下的所有包测试文件。
切片循环
在Go中提供了for range语法来快速迭代对象。数组、切片、字符串、map、channel等等类型都可以使用这种方式进行遍历,总结起来有以下几种形式:
只遍历不关心数据,适用于切片、数组、字符串、map、channel
for range T {}
遍历获取索引或数组,切片,数组、字符串就是索引,map就是key,channel就是数据
for key := range T{}
遍历获取索引和数据,适用于切片、数组、字符串,第一个参数就是索引,第二个参数就是对应的元素值,map 第一个参数就是key,第二个参数就是对应的值;
for key, value := range T{}
其实在实际开发中,我们会大概率会遇到遍历map时,只关心map中的数据,不关心key的情况。这个时候我们就是使用最后一种方式,这个key声明了但是没有用,Go这个时候就会提示一个语法错误key没有使用,那我们只好使用Go的另外一个语法糖_忽略标识符(就是一个下划线)忽略key,具体如下:
for _, value := range T{}
在Java中循环map的方式有很多种,但有一点就是,开发者可以使用keySet()、values()选择遍历key或者value。
// 打印键集合
for (String key : map.keySet()) {
System.out.println(key);
}
// 打印值集合
for (String value : map.values()) {
System.out.println(value);
}
另外注意一点,在Go中如果一个切片是nil的时候,我们对他进行遍历或者append操作的时候,是不会出现报错的,这一点很不错,省的像用Java时遍历对象需要判断他是否为null。
func main() {
temp := make([]int, 0)
temp = nil
for _, val := range temp {
fmt.Println("val=", val)
}
temp = append(temp, 1)
fmt.Println("val=", temp)
}
上述操作都是不会报错的,大家放心食用!
忽略变量、字段或者导包
这个前面提到了一点,使用_忽略变量。在Go中还有其他几种常见的场景,具体如下:
json序列化忽略某个字段 我们都会对struct做序列化操作,但有些时候我们想要json里面的某些字段不参加序列化,Go语言的结构体提供标签功能,在结构体标签中使用 - 操作符就可以对不需要序列化的字段做特殊处理,使用如下:
type Item struct{
Id uint32 `json:"id"`
Name string `json: "name"`
Password string `json: "-"`
}
这个Java中也有类似的实现,只要在Java类的属性前加上transient关键字修饰即可。当然在将Java类序列化成json时可以使用对应的注解,这里我就不细说了。
json序列化忽略空值字段 使用json.Marshal进行序列化时不会忽略struct中的空值(这里说的空值包含空字符串和nil),默认输出字段的类型零值(string类型零值是"",指针类型的零值是nil),如果我们想在序列化时忽略掉这些没有值的字段时,可以在结构体标签中中添加omitempty tag。
type Item struct{
Id uint32 `json:"id"`
Name string `json: "name,omitempty"`
Password string `json: "-"`
}
这里说一下,在Java里类型分为基本类型和包装类型,Java类初始化的时候属性为基本类型如果没有赋予初始值,默认值是0。包装类型声明时没有赋值的话的初始值为null。Go中初始化时没有赋值的变量的默认值如下:
- 布尔类型的默认为false
- 数值类型的默认为0
- 字符串类型的默认为空字符串""
- 指针类型、函数、接口、切片、通道和map默认值为nil
这样看来Java和Go这个场景下处理方式,有相似和不同之处,大家开发的时候要注意,由Java转Go的同学开发时,千万别搞混了。
短变量声明
在强类型语言中,声明一个变量都需要指定变量的类型。可能语言的开发者觉得这样做对开发者不太友好,就搞了个变量声明不用指定类型的语法糖,其实这个玩意说起来就是类型推导(Java8之后的版本貌似已经有了),开发者只管定义变量,类型由语言编译器来处理。
a := 10 #等用于 var a int = 10 #或者是 b:=fucName()
怎么说呢?这样有好处也有坏处,定义变量的人省事了,使用变量的人可能就懵逼了。就像这种场景b:=fucName(),这个 变量b是啥类型,这个时候你只能点击函数内,看函数的返回值类型是啥,才能确定变量b是啥类型。
我之前写过几年的PHP,后来转了Java,再到现在写Go。我发现各种开发语言都在进步,而且还相互模仿,PHP中函数之前不用指定形参类型,PHP8中好像可以指定形参类型了。总之就是强弱类型的语言在相互靠拢。
另类的返回值
在Go语言中,允许您使用return语句从一个函数返回多个值。换句话说,在函数中,单个return语句可以返回多个值。返回值的类型类似于参数列表中定义的参数的类型。
func func1(a string, b int) int {
fmt.Println("func1------------")
fmt.Println("a1 = ", a)
fmt.Println("b1 = ", b)
c := 100
return c
}
可以这样写:返回多个返回值,形参命名
func func2(a string, b int) (int, int) {
fmt.Println("func2------------")
fmt.Println("a2 = ", a)
fmt.Println("b2 = ", b)
return 12, 33
}
可以这样写:返回多个返回值,形参匿名
func func3(a string, b int) (int, int) {
fmt.Println("func3------------")
fmt.Println("a2 = ", a)
fmt.Println("b2 = ", b)
return 12, 33
}
如果一个函数要返回多个值,在Java中可以使用定义一个新的类来承载返回值,或者偷个懒使用map来接也是可以的。go支持多个返回值就我个人来说还是支持的。其实说到这里,多个返回值的各种形式都能理解。直到有一天我在翻看gorm的Open方法源码发现了奇怪的地方,代码位置信息:gorm.io/gorm@v1.23.4/gorm.go:116 ,节选部分代码如下:
func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
config := &Config{}
if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
if err = d.Apply(config); err != nil {
return
}
}
# 省略此处无用代码
db = &DB{Config: config, clone: 1}
db.callbacks = initializeCallbacks(db)
# 省略此处无用代码
preparedStmt := &PreparedStmtDB{
ConnPool: db.ConnPool,
Stmts: map[string]Stmt{},
Mux: &sync.RWMutex{},
PreparedSQL: make([]string, 0, 100),
}
db.cacheStore.Store(preparedStmtDBKey, preparedStmt)
# 省略此处无用代码
db.Statement = &Statement{
DB: db,
ConnPool: db.ConnPool,
Context: context.Background(),
Clauses: map[string]clause.Clause{},
}
# 省略此处无用代码
return
}
这就是文章开头提到的让人懵逼的语法糖,我当时看到这段代码时,我心中暗想这个是什么TM操作,竟然这样也行,这样竟然没有报错…… 我来点出其中的问题,就是return关键字处并没有返回db和error变量。我把上述代码在简化一下,用最简单的方式列出来,如下:
func func4(a string, b int) (r1 int, r2 int) {
fmt.Println("func4------------")
//r1 r2输入fool3的形参,初始化默认的值是0
//r1 r2 作用域空间是 func4 整个函数体的{}空间
fmt.Println("r1 = ", r1)
fmt.Println("r2 = ", r2)
r1 = b * 2
r2 = 2000
return
}
上述这种方式其实本质上来说是和前面几种方式一样,只是在不知道这种约定的话,会让人难以理解。知道这个算是Go中的小tips之后,咱也不知道Go为啥要这么做,只是觉得有点懵,我只是觉得在Java中绝对不会出现这种情况。但是在Go中也许是设计Go的大佬们觉得这样做可以省掉声明变量r1和r2的时间,毕竟大佬们的时间都很宝贵。
总结
本文介绍了一些Go语言中的语法糖,当然并不全面,应该还有其他的没有介绍,希望大家能够看完本篇文章后,能了解并掌握,并能在实际开发中运用到,当然其中的函数多返回值的懵逼写法,就由大家自行判断是用还是不用了。
以上就是《一起聊聊Go语言中的语法糖的使用》的详细内容,更多关于golang的资料请关注golang学习网公众号!
Golang文件读写操作详情
- 上一篇
- Golang文件读写操作详情
- 下一篇
- Go语言中的数据格式(json、xml 、msgpack、protobuf)使用总结
-
- Golang · Go教程 | 6小时前 | 格式化输出 printf fmt库 格式化动词 Stringer接口
- Golangfmt库用法与格式化技巧解析
- 140浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang配置Protobuf安装教程
- 147浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Golang中介者模式实现与通信解耦技巧
- 378浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang多协程通信技巧分享
- 255浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang如何判断变量类型?
- 393浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Golang云原生微服务实战教程
- 310浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang迭代器与懒加载结合应用
- 110浏览 收藏
-
- Golang · Go教程 | 8小时前 | 性能优化 并发安全 Golangslicemap 预设容量 指针拷贝
- Golangslicemap优化技巧分享
- 412浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang代理模式与访问控制实现解析
- 423浏览 收藏
-
- Golang · Go教程 | 8小时前 |
- Golang事件管理模块实现教程
- 274浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3166次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3379次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3408次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4512次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3788次使用
-
- 一起聊聊Go语言中的语法糖的使用
- 2023-01-24 126浏览

