官方指路
我的第一个Go程序
- 相信大家的第一个程序都源于一个简单但令人开心的
Hello World
,那么我们的第一个Go
程序也从Hello World
开始
go
package main
import "fmt"
func main() {
/* 我的第一个Go程序 */
fmt.Println("Hello, World!")
}
-
如果你使用的是
JetBrains
的GoLand
,点击绿色的运行按钮,就可以在控制台看到了你的第一个程序发出的信息 -
如果不是/你想用控制台对这个程序进行编译,我们可以这样
bash
# 注意,这里的hello.go是你编写的go文件名字
$ go run hello.go
Hello, World!
-
很像
Python
,对吧?我们可以通过go run $filename$
的形式直接编译并执行这样一个文件 -
但是如果要像
Java
那样先编译成二进制文件再执行,又该怎么操作呢?
bash
$ go build hello.go
# 这个hello,就是编译出来的二进制文件
$ ls
hello hello.go
$ ./hello
Hello, World!
- 这样的效果是一样的
分析一下Hello World
- 别看这样的一个程序简单,实际上它具备了一般Go程序的大部分结构,让我们一行行分析原来的
hello.go
go
package main
- 这一行代码定义了包名,我们必须在源文件的第一行(不包括注释哦)指明这个文件属于哪个包。
package main
表示这是一个可独立执行的程序,每个Go
应用程序都必须包含一个名为main
的包
go
import "fmt"
- 这一行告诉了Go编译器这个程序需要使用
fmt
包,fmt
包实现了格式化I/O
与其相关的函数
go
func main(){
...
}
-
与其它语言相同,这一行是程序的入口,表示程序从这里开始执行。除了
init
函数,main
一般是程序中第一个执行的函数 -
注意函数的大括号一定要紧跟小括号 ,像
C/C++
不同行的形式是不被允许的
go
/* 我的第一个Go程序 */
- 这一行是语言中的注释,与其它语言相同
//...
表示单行注释,/* ... */
表示多行注释
go
fmt.Println("Hello World!")
- 将字符输出到控制台,这行代码相当于
go
fmt.Print("Hello World!\n")
- 标识符(常量、变量类型、函数名、结构字段等)如果以大写字母开头 ,例如下文实验中的
Func1
,使用这种形式的标识符对象可以被外部包的代码使用 (详情可以参考下文实验),类似于其它语言中的public
属性;但是如果以小写字母开头 ,则对外部包不可见(即使已经在开头导入),但是该标识符对象在整个包的内部仍然可用,类似其它语言中的private
属性。(试试把下文中的Func1
改为func1
,看看是否还能正常工作?)
注意
-
文件名与包名没有直接关系 :像是我们之前的哪个
hello.go
,它的文件名和包名main
并不相同 -
文件夹名和包名没有直接关系 :别看
Java
里包装时需要package
的名称和文件夹需要严格一致,Go
则自由得多 -
同一个文件夹下的文件只能有一个包名,否则编译报错
-
为了验证以上说法,我们可以进行这样一个实验
bash
# 建立一个这样的文件结构
- hello.go
- Another
-- Class1.go
-- Class2.go
- 在
hello.go
中调用Another
文件夹下两个程序的函数,看看会发生什么
go
package main
import (
"fmt"
"./Another"
)
func main(){
fmt.Println("Hello World!")
fmt.Println(AnotherPackage.Func1())
fmt.Println(AnotherPackage.Func2())
}
Another
中两个程序的内容
go
// Class1.go
package AnotherPackage
func Func1() string {
return "This is func1 in Another from AnotherPackage!"
}
// Class2.go
package AnotherPackage
func Func2() string {
return "This is func2 in Another from AnotherPackage!"
}
- 运行一下
bash
$ go run hello.go
- 结果输出如下
-
这里的
Class1.go
和Class2.go
都在package AnotherPackage
下,但是文件夹又和它名字不同,可以看到是可以正常运行的 -
为了验证第三点,我们把
Class2.go
的内容修改一下
go
package NoPackage
func Func2() string {
return "This is func2 in Another from AnotherPackage!"
}
- 再次运行,看看如何?
- 不出所料报错了。证明虽然
Go
允许文件夹和包名不同,但必须保证一个文件夹下的所有文件的包名必须相同
基础知识
标记
-
Go
程序一定由多个标记组成,常见的标记有-
关键字:struct,func,go,val等
-
标识符:main,Println等
-
常量:1234,"字符串"等
-
符号:. {} 等
-
行分割符
-
类似于其它脚本语言,
Go
程序无需分号进行每行语句的分隔,对每行语句的解析都由编译器自己进行 -
但如果你又希望像
C/C++
那样酷炫的压行写法,Go
也支持带有分号的语义分析。也就是说,如果你希望在同一行里写下多行语句,此时就必须使用分号分隔了(但是Go的开发者没有这样的坏习惯,它们一般都分多行书写,毕竟这样更简洁明了,不是吗?)
注释
- 单行与多行注释的语法和
C/C++
完全相同。还是那句话,咱只讨厌两种人,一种是不写注释的别人,和要求自己写注释的笨蛋。
标识符
- 和一般的语言相同,标识符用于命名程序实体。规则也相似,一般以字母或下划线开头
go
// 合法的标识符
hello he12 heas___ _dsadas _111
// 非法标识符
123(数字开头) func(关键字) 9+8(含有运算符)
字符串连接
- 和
Java
相同,两个字符串可以直接使用+
号连接
go
package main
import "fmt"
func main(){
fmt.Println("Hello"+" "+"World"+"!")
}
关键字
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
预定义标识符
append | bool | byte | cap | close | complex |
---|---|---|---|---|---|
complex64 | complex128 | uint16 | copy | false | float32 |
float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new |
nil | panic | uint64 | println | real | |
recover | string | true | uint | uint8 | uintptr |
空格
-
为了提高代码的可读性,我们都会在程序里各个地方加上空格,毕竟谁都不想看到堆在一起的代码.....对吧?
-
Go
中变量的声明必须使用空格隔开
go
var x string
const Pi float64 = 3.1415926
- 关键字和表达式之间也要用空格隔开
go
if 2 < 3 {
...
}
- 函数调用时,函数名和等号之间也要有空格,函数的参数之间也要有空格
go
result := add(2, 3)
- 如果你使用的是
GoLand
,那么这些你都无需担心,IDE
会帮助你做好格式化代码的工作