Go语言学习教程之声明语法(译)
作者:Rob Pike 发布时间:2024-02-01 03:44:16
前言
学习一门新的语言肯定是要从他的基本语法开始,语法构成了整个程序设计的基础,从语法中我们也可以看到这门语言的一些特性,但是话说回来,语法这东西,不同的语言大同小异,所以这也对语法的记忆造成了一定的难度,其实最好的方法应该是旁边有本书,随时可以拿过来查阅或者纠正。
Go 的初学者可能会有这样的疑问:为什么 Go 的声明语法与传统的其他 C 家族编程语言不太一样?在这篇文章中我们会比较这两种不同的方式,并且也会解释为什么。下面话不多说了,来一起看看详细的介绍吧。
C 变量
首先,让我们说说 C 中的语法。C 使用了一种不寻常的巧妙的方法来实现声明语法。我们不是用什么特殊的语法来描述类型,而是写一个表达式,这个表达式包含两个部分:被声明的变量和变量的类型。
int x;
上面这行代码声明了一个类型为 int 的变量 x。一般来说,为了弄清楚如何编写新变量的类型,可以先写一个含基本类型变量的表达式,然后将基本类型放在左边,将表达式放在右边。
因此,下面的声明:
int *p;
int a[3];
描述的是 p 是一个指向 int 类型的指针,因为 ‘*p' 的类型为 int。而 a 是一个 int 类型的数组,因为 ‘a[3]' (这里请忽略下标的值 3,它只是说明数组的大小)的类型是 int。
那函数呢?在最开始的时候,C 的函数声明是将 参数的类型写在括号外面的,像这样:
int main(argc, argv)
int argc;
char *argv[];
{ /* ... */ }
再一次,我们可以看到 main 是一个函数,因为表达式 main(argc, argv) 返回了一个 int 类型的值。现在大家比较习惯写成这样:
int main(int argc, char *argv[]) { /* ... */ }
但是基本的结构还是一样的。
对于简单的类型来说这种巧妙的语法思想是能很好工作的,但是一旦类型变得复杂就会令人感到困惑了。非常经典的一个例子就是声明一个函数指针。遵循着规则,你得到了下面的这种写法:
int (*fp)(int a, int b);
fp 是一个指向函数的指针,因为如果你写一个表达式 (*fp)(a, b) 你会调用函数并得到一个 int 类型的值。那如果 fp 的其中一个入参它本身也是一个函数呢?
int (*fp)(int (*ff)(int x, int y), int b)
这就变得开始难以阅读了。
当然,我们可以在声明一个函数的时候去掉参数名,那么 main 函数可以声明成:
int main(int, char *[])
让我们回想一下,argv 是这样声明的,
char *agrv[]
通过把变量名放在中间来声明类似 char *[] 这样类型的时候其实是令人困惑的。
然后我们再来看看如果我们将入参变量名去掉的情况下 fp 函数的声明是怎么样的:
int (*fp)(int (*)(int, int), int)
无论将变量名放在内部的哪里都不那么清晰明了。对于第一个入参:
int (*)(int, int)
我想这不太容易能一眼看出是在声明一个指向函数的指针。再进一步,如果我们的返回值也是一个函数指针呢?
int (*(*fp)(int (*)(int, int), int))(int, int)
这根本就看不清声明出来的 fp 到底是个啥玩意。。。
你自己也可以构造出更多这类详细的例子,但是这些都说明了 C 的声明语法可能引入的一些困难。
不过还有一点需要提出。因为类型和声明的语法是相同的,所以解析中间类型的表达式是很困难的。这就是为什么 C 的类型转换总是用括号括起来:
(int)M_PI
Go 语法
非 C 家族的编程语言通常使用不同的声明类型的语法:变量名通常放在前面,然后紧跟着一个冒号。因此我们上面的例子就变成了这样:
x: int
p: pointer to int
a: array[3] of int
这些声明是明确的,如果从左往右读你会发现也是详细的。Go 语言从中得到了启发,但为了简洁起见,删除了冒号和一些关键字:
x int
p *int
a [3]int
这个例子中 [3]int 与如何在表达式中使用 a 这两者似乎没有直接的对应。(后面一小节中我们会讲到指针的。)你可以通过单独的语法来获得清晰的结果。
现在让我们考虑下函数。让我们把这个声明写成 Go 的形式,尽管在 Go 中真正的 main 函数是没有入参的:
func main(argc int, argv []string) int
表面上这和 C 语言并没什么不同,除了将字符数组改成了字符串形式。但是从左往右读起来却很顺畅:
函数 main 需要传入一个整型和字符串切片并且返回一个整型。(译者注:直到译者看到这篇文章,译者才发现原来这么写读起来竟这么顺畅。。。)
即便舍去变量名还是很明确——因为对于类型声明上没有位置的变化,所以也没有什么困惑。
func main(int, []string) int
这种从左到右的风格有一个优点:就算类型变得越来越复杂,这种方式还是表现得很得当。
举个声明函数变量的例子(类似在 C 语言中的函数指针):
f func(func(int, int) int, int) int
或者如果 f 返回的也是一个函数(译者注:边写边读你会再次惊讶于这丝滑般的顺畅感。。。):
f func(func(int, int) int, int) func(int, int) int
从左到右依然读起来很顺畅,并且当变量名被声明的时候也很明显。
类型和表达式的语法的不同点使得在 Go 中编写和调用闭包是那么的简单:
sum := func(a, b int) int { return a + b } (3, 4)
指针
指针这家伙总是表现得“与众不同”一点。观察下数组和切片,举个例子,Go 的类型语法将方括号放在类型的左边,但是赋值表达式语法却是将其放在表达式的右边:
var a []int
x = a[1]
为了让大家有一种熟悉的感觉,Go 的指针同样延续 C 语言中的 * 符号,但是我们不能简单的将指针类型也反转一下。所以指针使用方式如下:
var p *int
x = *p
我们不能简单粗暴地改成这样:
var p *int
x = p*
因为后缀 会与乘法的 相混淆。那或许我们可以使用 ^,举个例子:
var p ^int
x = p^
但同样的这个符号也已经有其他含义了,类型和表达式在前缀后缀的问题上总是在许多方面使事情复杂化。举个例子,
[]int("hi")
这是一种写法,但一旦以 * 打头就必须用括号将其包住:
(*int)(nil)
如果我们愿意放弃 * 作为指针语法,那么这些括号就不是必要的了。(译者注:但还能有更好的指针语法吗。。。)
所以 Go 的指针语法与熟悉的 C 语言是类似的,但这个关联也意味着我们不得不使用括号来消除语法中的类型和表达式之间的差异。
总体而言,我们相信 Go 的类型语法比 C 的要更容易理解,尤其是当事情变得复杂的时候。
关于Go语言为何要采用这种倒序语法呢?
Go的设计者Rob Pike的一篇介绍Go声明语法的文章给出了答案,其中谈到了Go声明语法的设计考量。
来源:https://blog.go-zh.org/gos-declaration-syntax
猜你喜欢
- 有时候在使用Python处理比较耗时操作的时候,为了便于观察处理进度,这时候就需要通过进度条将处理情况进行可视化展示,以便我们能够及时了解情
- 保留COOKIES一个小时Response.Cookies("MyCookie").Expires= (now
- 本文实例讲述了Python设计模式之工厂模式。分享给大家供大家参考,具体如下:工厂模式是一个在软件开发中用来创建对象的设计模式。工厂模式包涵
- 人脸美白原理人脸美白原理说透了,就是一种图像的颜色空间处理,所以我们需要通过颜色空间进行设计。不过,我们先来参考以下PS对于图像美白的处理步
- 通常人们使用以下两种方法来执行SQL语句: Set Rs=Conn.Execute(SqlStr) 和&nbs
- NumPy广播(Broadcast),广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的
- 这篇分享几个在地址栏实现的Javascript有趣效果和应用。能在浏览器地址栏实现的效果太多了,字体放大、显示所有图片、显示Cookie等等
- NetworkX是一个非常强大的网络科学工具,它封装了图的数据结构和许多经典图算法,也内置了许多可视化函数可供调用。1. 随机图生成最经典的
- 本文实例讲述了Python图像处理之直线和曲线的拟合与绘制。分享给大家供大家参考,具体如下:在数据处理和绘图中,我们通常会遇到直线或曲线的拟
- 本文实例为大家分享了python实现电子词典的具体代码,供大家参考,具体内容如下# -*- coding: utf-8 -*-#youdan
- CSS制作滑动折叠的文字效果,可以用于二级导航菜单的制作,不错的下拉菜单。<!DOCTYPE html PUBLIC "-/
- 前言在服务部署在mysql上应该有好几个月了,因为现在的工作基本都在终端,因此很少登陆,今天要修改个东西,忽然发现我竟然已经彻底忘记了mys
- 一、实验名称建立聊天工具二、实验目的掌握Socket编程中流套接字的技术,实现多台电脑之间的聊天。三、实验内容和要求vii.掌握利用Sock
- 1、准备工作准备三张表,一张角色表,一张装备表,一张基础数据表,这里只展示一些教程中需要的字段,在游戏开发的过程中肯定不止这么几个字段,我想
- 本文实例为大家分享了python实现自主查询实时天气的具体代码,供大家参考,具体内容如下用到了urllib2 json 很简单的
- 1、get方式:如何为爬虫添加ip代理,设置Request header(请求头)import urllib import urllib.r
- Dreamweaver从出道以来,其简便易用而又功能强大的“行为”(Behavior)一直是大家所关注的热点之一。在Dreamweaver
- XML同HTML一样,都来自Standard Generalized Markup Language, 即标准通用标记语言,简称SGML。早
- 会员注册以后,有些会员可能会遇到忘记登录密码的问题,因而网站具备“找回密码/忘记密码”功能不仅是必须的,而且是服务贴心的具体表现之一。在此,
- 粒子群算法是一种基于鸟类觅食开发出来的优化算法,它是从随机解出发,通过迭代寻找最优解,通过适应度来评价解的品质。PSO算法的搜索性能取决于其