- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Go语言学习教程之声明语法(译)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
学习一门新的语言肯定是要从他的基本语法开始,语法构成了整个程序设计的基础,从语法中我们也可以看到这门语言的一些特性,但是话说回来,语法这东西,不同的语言大同小异,所以这也对语法的记忆造成了一定的难度,其实最好的方法应该是旁边有本书,随时可以拿过来查阅或者纠正.
Go 的初学者可能会有这样的疑问:为什么 Go 的声明语法与传统的其他 C 家族编程语言不太一样?在这篇文章中我们会比较这两种不同的方式,并且也会解释为什么。下面话不多说了,来一起看看详细的介绍吧.
C 变量 。
首先,让我们说说 C 中的语法。C 使用了一种不寻常的巧妙的方法来实现声明语法。我们不是用什么特殊的语法来描述类型,而是写一个表达式,这个表达式包含两个部分:被声明的变量和变量的类型.
1
|
int
x;
|
上面这行代码声明了一个类型为 int 的变量 x。一般来说,为了弄清楚如何编写新变量的类型,可以先写一个含基本类型变量的表达式,然后将基本类型放在左边,将表达式放在右边.
因此,下面的声明:
1
2
|
int
*p;
int
a[3];
|
描述的是 p 是一个指向 int 类型的指针,因为 ‘*p' 的类型为 int。而 a 是一个 int 类型的数组,因为 ‘a[3]' (这里请忽略下标的值 3,它只是说明数组的大小)的类型是 int.
那函数呢?在最开始的时候,C 的函数声明是将 参数的类型写在括号外面的,像这样:
1
2
3
4
|
int
main(argc, argv)
int
argc;
char
*argv[];
{
/* ... */
}
|
再一次,我们可以看到 main 是一个函数,因为表达式 main(argc, argv) 返回了一个 int 类型的值。现在大家比较习惯写成这样:
1
|
int
main(
int
argc,
char
*argv[]) {
/* ... */
}
|
但是基本的结构还是一样的.
对于简单的类型来说这种巧妙的语法思想是能很好工作的,但是一旦类型变得复杂就会令人感到困惑了。非常经典的一个例子就是声明一个函数指针。遵循着规则,你得到了下面的这种写法:
1
|
int
(*fp)(
int
a,
int
b);
|
fp 是一个指向函数的指针,因为如果你写一个表达式 (*fp)(a, b) 你会调用函数并得到一个 int 类型的值。那如果 fp 的其中一个入参它本身也是一个函数呢?
1
|
int
(*fp)(
int
(*ff)(
int
x,
int
y),
int
b)
|
这就变得开始难以阅读了.
当然,我们可以在声明一个函数的时候去掉参数名,那么 main 函数可以声明成:
1
|
int
main(
int
,
char
*[])
|
让我们回想一下,argv 是这样声明的, 。
1
|
char
*agrv[]
|
通过把变量名放在中间来声明类似 char *[] 这样类型的时候其实是令人困惑的.
然后我们再来看看如果我们将入参变量名去掉的情况下 fp 函数的声明是怎么样的:
1
|
int
(*fp)(
int
(*)(
int
,
int
),
int
)
|
无论将变量名放在内部的哪里都不那么清晰明了。对于第一个入参:
1
|
int
(*)(
int
,
int
)
|
我想这不太容易能一眼看出是在声明一个指向函数的指针。再进一步,如果我们的返回值也是一个函数指针呢?
1
|
int
(*(*fp)(
int
(*)(
int
,
int
),
int
))(
int
,
int
)
|
这根本就看不清声明出来的 fp 到底是个啥玩意。。.
你自己也可以构造出更多这类详细的例子,但是这些都说明了 C 的声明语法可能引入的一些困难.
不过还有一点需要提出。因为类型和声明的语法是相同的,所以解析中间类型的表达式是很困难的。这就是为什么 C 的类型转换总是用括号括起来:
1
|
(
int
)M_PI
|
Go 语法 。
非 C 家族的编程语言通常使用不同的声明类型的语法:变量名通常放在前面,然后紧跟着一个冒号。因此我们上面的例子就变成了这样:
1
2
3
|
x:
int
p: pointer to
int
a: array[3] of
int
|
这些声明是明确的,如果从左往右读你会发现也是详细的。Go 语言从中得到了启发,但为了简洁起见,删除了冒号和一些关键字:
1
2
3
|
x
int
p *
int
a [3]
int
|
这个例子中 [3]int 与如何在表达式中使用 a 这两者似乎没有直接的对应。(后面一小节中我们会讲到指针的。)你可以通过单独的语法来获得清晰的结果.
现在让我们考虑下函数。让我们把这个声明写成 Go 的形式,尽管在 Go 中真正的 main 函数是没有入参的:
1
|
func main(argc
int
, argv []string)
int
|
表面上这和 C 语言并没什么不同,除了将字符数组改成了字符串形式。但是从左往右读起来却很顺畅:
函数 main 需要传入一个整型和字符串切片并且返回一个整型。(译者注:直到译者看到这篇文章,译者才发现原来这么写读起来竟这么顺畅。。。) 。
即便舍去变量名还是很明确——因为对于类型声明上没有位置的变化,所以也没有什么困惑.
1
|
func main(int, []string) int
|
这种从左到右的风格有一个优点:就算类型变得越来越复杂,这种方式还是表现得很得当.
举个声明函数变量的例子(类似在 C 语言中的函数指针):
1
|
f func(func(int, int) int, int) int
|
或者如果 f 返回的也是一个函数(译者注:边写边读你会再次惊讶于这丝滑般的顺畅感。。。):
1
|
f func(func(int, int) int, int) func(int, int) int
|
从左到右依然读起来很顺畅,并且当变量名被声明的时候也很明显.
类型和表达式的语法的不同点使得在 Go 中编写和调用闭包是那么的简单:
1
|
sum := func(a, b
int
)
int
{
return
a + b } (3, 4)
|
指针 。
指针这家伙总是表现得“与众不同”一点。观察下数组和切片,举个例子,Go 的类型语法将方括号放在类型的左边,但是赋值表达式语法却是将其放在表达式的右边:
1
2
|
var a []
int
x = a[1]
|
为了让大家有一种熟悉的感觉,Go 的指针同样延续 C 语言中的 * 符号,但是我们不能简单的将指针类型也反转一下。所以指针使用方式如下:
1
2
|
var p *
int
x = *p
|
我们不能简单粗暴地改成这样:
1
2
|
var p *
int
x = p*
|
因为后缀 会与乘法的 相混淆。那或许我们可以使用 ^,举个例子:
1
2
|
var p ^
int
x = p^
|
但同样的这个符号也已经有其他含义了,类型和表达式在前缀后缀的问题上总是在许多方面使事情复杂化。举个例子, 。
1
|
[]
int
(
"hi"
)
|
这是一种写法,但一旦以 * 打头就必须用括号将其包住:
1
|
(*
int
)(nil)
|
如果我们愿意放弃 * 作为指针语法,那么这些括号就不是必要的了。(译者注:但还能有更好的指针语法吗。。。) 。
所以 Go 的指针语法与熟悉的 C 语言是类似的,但这个关联也意味着我们不得不使用括号来消除语法中的类型和表达式之间的差异.
总体而言,我们相信 Go 的类型语法比 C 的要更容易理解,尤其是当事情变得复杂的时候.
关于Go语言为何要采用这种倒序语法呢?
Go的设计者Rob Pike的一篇介绍Go声明语法的文章给出了答案,其中谈到了Go声明语法的设计考量.
总结 。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持.
原文链接:https://blog.go-zh.org/gos-declaration-syntax 。
最后此篇关于Go语言学习教程之声明语法(译)的文章就讲到这里了,如果你想了解更多关于Go语言学习教程之声明语法(译)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在使用 go 图表库 https://github.com/wcharczuk/go-chart制作条形图。我面临的问题是标签值很长,我想将文本旋转 45 度以显示完整文本 我喜欢显示的日期格式是
我在构建一个非常简单的通过 cgo 调用 c 代码的 go 程序时遇到了问题。我的设置: $: echo $GOPATH /go $: pwd /go/src/main $: ls ctest.c
没有 C 的背景,只有 Go 的“初学者”经验,我正在尝试弄清楚 main.go 是实际需要的还是只是一个约定。 我想创建一个简单的网络 API,但有人可以为我澄清一下吗? 最佳答案 main.go
我read从 Go 1.4 开始,Go 运行时是用 Go 本身编写的(而不是用 C)。 这怎么可能?如果 Go 程序在运行时之上运行,并且运行时是 Go 程序,那么运行时是否在自身之上运行? 最佳答案
这是“Go 之旅”中的代码示例 Range and Close : package main import ( "fmt" ) func fibonacci(n int, c chan int
给定以下 go.mod 文件: module foo go 1.12 require ( github.com/bar/baz v1.0.0 github.com/rat/cat v1
我有一个 CI/CD 管道,它需要跨平台并与几个不同的管理程序一起工作。为了不必更改 Windows 和 Linux 的构建任务,我认为 Go 将是编写一次代码并在任何地方运行的好方法。然而,考虑到
我有一个 Dockerfile,用于使用 go build 编译 Go 应用程序。我进行了研究,确实建议将 go build 用于生产。 但是我找不到正确的答案来解释为什么。 我了解 go run 创
我尝试在命令提示符#Go lang 中运行该程序-但是当我键入运行“go run hello.go”命令时,我开始了 CreateFile hello.go:The system cannot fin
我正在使用“Go 编程语言”一书学习 Go。第一章介绍os.Open用于读取文件的模块。我尝试打开如下所示的 go 文件。 f, err = os.Open("helloworld.go") 我收
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题?通过 editing this post 添加详细信息并澄清问题. 2年前关闭。 Improve this
为了解决我对 goroutine 的一些误解,我去了 Go 操场跑了 this code : package main import ( "fmt" ) func other(done cha
这个问题在这里已经有了答案: Evaluate/Execute Golang code/expressions like js' eval() (5 个回答) 1年前关闭。 对于任何 go 程序,我想
这是我基本上试图从路径打印基准的代码。 这意味着,如果用户输入“/some/random/path.java”,则输出将为“path”。同样,如果用户arg为“/another/myapp.c”,则输
$ go version 1.13.3 我的文件夹结构如下: GOPATH +---src +--- my-api-server +--- my-auth-server
这个问题在这里已经有了答案: How to embed file for later parsing execution use (4 个答案) What's the best way to bun
我觉得这有点奇怪,为什么这段代码不起作用? package main import "fmt" func main() { var i, j int = 1, 2 k
go编译器执行完如下命令后的可执行文件存放在哪里? $> go run file.go 最佳答案 在 /tmp 文件夹中,如果您使用的是 unix 机器。 如果您使用的是 Windows,则在 \Us
我目前正在开始使用 Go,并且已经深入研究了有关包命名和工作区文件夹结构的注意事项。 不过,我不太确定如何根据 Go 范式正确组织我的代码。 这是我当前的结构示例,它位于 $GOPATH/src 中:
假设我有一个接受用户输入的 Lua 程序,而该输入恰好是有效的 Lua 源代码。这是在程序仍在运行时进行清理、编译和执行的。 Go 是否(或将)实现这样的事情? 最佳答案 我认为以下两个项目之间有足够
我是一名优秀的程序员,十分优秀!