在学习Hyperleger Fabric框架时为了看代码和改代码时轻松一些,自学了一下Go语言,参考的是菜鸟教程。我自己比较熟悉的语言是C++,所以在学习Go时经常与C++做一下对比,这样学的也轻松一些。
1.程序基本结构
Go 语言的基础组成有以下几个部分:
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
以Hello World为例:
package main
import "fmt"
func main() {
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")
}
-
第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
-
下一行 import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。import相当于C++的include,声明该程序引入的包(库),特殊的是main包一定是要有的,即程序一定要有main函数。
-
下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。注意main函数写法“func”+“main”,这里没有返回类型因为main函数不需要返回值。
-
下一行 /*...*/ 是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。注释方式与C++相同。
-
下一行 fmt.Println(...) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
使用 fmt.Print("hello, world\n") 可以得到相同的结果。
Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。fmt即控制格式化输入输出的包,作用类似于C++的iostream。 -
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。这种写法比较特殊,大写字母开头的标识符相当于C++中用public修饰的,小写字母开头相当于被protected修饰。
Go程序的执行与其他编译型语言一样,可以用一条命令编译并运行得到结果,也可以先编译生成可执行文件,然后启动可执行文件得到结果。
1.输入命令 go run hello.go 并按回车执行代码。
$ go run hello.go
Hello, World!
2.我们还可以使用 go build 命令来生成二进制文件:
$ go build hello.go
$ ls
hello hello.go
$ ./hello
Hello, World!
需要注意的是 { 不能单独放在一行,所以以下代码在运行时会产生错误(这点得尤其注意,我C++一直都是这样写的。。):
package main
import "fmt"
func main()
{ // 错误,{ 不能在单独的行上
fmt.Println("Hello, World!")
}
2.Go语言基础语法
Go 标记
Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号。如以下 GO 语句由 6 个标记组成:
fmt.Println("Hello, World!")
6 个标记是(每行一个):
1. fmt
2. .
3. Println
4. (
5. "Hello, World!"
6. )
行分隔符
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。
以下为两个语句:
fmt.Println("Hello, World!")
fmt.Println("菜鸟教程:runoob.com")
标识符
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
以下是有效的标识符:
mahesh kumar abc move_name a_123
myname50 _temp j a23b9 retVal
标识符规则也与C++相同,要特别注意大写开头与小写开头造成的“public”和“protected”效果。
字符串连接
Go 语言的字符串连接可以通过 + 实现:
package main
import "fmt"
func main() {
fmt.Println("Google" + "Runoob")
}
以上实例输出结果为:
GoogleRunoob
关键字
下面列举了 Go 代码中会使用到的 25 个关键字或保留字:
除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:
程序一般由关键字、常量、变量、运算符、类型和函数组成。
程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。
程序中可能会使用到这些标点符号:.、,、;、: 和 …。
格式化字符串
Go 语言中使用 fmt.Sprintf 格式化字符串并赋值给新串:
package main
import (
"fmt"
)
func main() {
// %d 表示整型数字,%s 表示字符串
var stockcode=123
var enddate="2020-12-31"
var url="Code=%d&endDate=%s"
var target_url=fmt.Sprintf(url,stockcode,enddate)
fmt.Println(target_url)
}
输出结果为:
Code=123&endDate=2020-12-31
3.Go 语言变量
变量来源于数学,是计算机语言中能储存计算结果或能表示值抽象概念。
变量可以通过变量名访问。
Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
声明变量的一般形式是使用 var 关键字:
var identifier type
var identifier1, identifier2 type
示例:
package main
import "fmt"
func main() {
var a string = "Runoob"
fmt.Println(a)
var b, c int = 1, 2
fmt.Println(b, c)
}
以上实例输出结果为:
Runoob 1 2
未初始化的变量数值为零值,此处零值不都指数值0,意义如下:
-
数值类型(包括complex64/128)为 0
-
布尔类型为 false
-
字符串为 ""(空字符串)
-
以下几种类型为 nil(nil类似于C++的NULL):
var a *int
var a []int
var a map[string] int
var a chan int
var a func(string) int
var a error // error 是接口
Go语言可以根据值自行判定变量类型:
package main
import "fmt"
func main() {
var d = true
fmt.Println(d)
}
输出结果:
true
还可以用:=声明变量同时初始化:
intVal := 1 相等于
var intVal int
intVal =1
可以将 var f string = "Runoob" 简写为 f := "Runoob":
package main
import "fmt"
func main() {
f := "Runoob" // var f string = "Runoob"
fmt.Println(f)
}
输出结果:
Runoob
注意这种简写方式只能写在函数体中,即不能用来声明全局变量。
如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量 a:
package main
import "fmt"
func main() {
var a string = "abc"
fmt.Println("hello, world")
}
尝试编译这段代码将得到错误 a declared but not used。
此外,单纯地给 a 赋值也是不够的,这个值必须被使用,所以使用
fmt.Println("hello, world", a)
会移除错误。全局变量是允许声明但不使用的。
这个局部变量声明了就一定要使用的规则是C++没有的,编写程序时需要额外注意。
4.Go语言常量
常量在声明时的写法和C++没什么区别,这里介绍一下枚举写法和特殊常量iota。
枚举
const (
Unknown = 0
Female = 1
Male = 2
)
数字 0、1 和 2 分别代表未知性别、女性和男性。
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:
package main
import "unsafe"
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(a)
)
func main(){
println(a, b, c)
}
以上实例运行结果为:
abc 3 16
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
iota 可以被用作枚举值:
const (
a = iota
b = iota
c = iota
)
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:
const (
a = iota
b
c
)
iota相当于const的行索引,在新的一行就加1。
看个有趣的的 iota 实例:
package main
import "fmt"
const (
i=1<<iota
j=3<<iota
k
l
)
func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
以上实例运行结果为:
i= 1 j= 6 k= 12 l= 24
iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。可以看到k和l是顺着3<<iota进行赋值的。
5.运算符
Go语言的运算符与C++完全相同,这里就不记录了~
6.总结
第一章学习记录包含了Go语言基础结构、基础语法以及变量和常量的介绍,总体学习下来感觉Go语言的编写有它比较方便的地方,比如声明局部变量的简写、iota这个特殊常量的运用等;不过一些规则的限制也显得写程序没那么自由,比如左花括号“{”不能单独成行、简写不能用于全局变量、声明的局部变量一定要被使用等,这就需要我改变一下写C++时保留的一些习惯了。