Re:从零开始的 Go 之旅-基本语法

本文最后更新于 2025年1月20日 凌晨

GoGoGo!

先看一个简单的代码,熟悉一下简单语法

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
fmt.Println("Hello butt3rf1y!")
}

package:声明当前文件属于哪一个包,入口文件都必须为 main,入口函数是 main 函数。

import:导入关键字,fmt 是导入的包名。

func:函数声明关键字。

在 go 中,程序通过将包链接在一起来构建,go 中导入的最基本单位是一个,不是 .go 文件。包内共享所有变量,常量以及所有定义的类型,而且包名建议小写。

可见性

go 中控制包内资源可见性有两种方法

  1. 名称大写字母开头,即为公有
  2. 小写或下划线开头,即为私有
1
2
3
4
5
package butt3r

const User = "butt3rf1y" //公有

const passwd = 114514 //私有

导入

导入包就是导入这个包的所有公有的类型/变量/常量

1
import 包名

导入单个包时

1
2
3
package main

import "example"

导入多个包时

1
2
3
4
package main

import "example"
import "example2"

导入多个包时也可以用 {} 括起来

1
2
3
4
5
6
package main

import (
"example"
"example1"
)

如果包名重复或比较复杂,可以起一个别名

1
2
3
4
5
6
package main

import (
e "example"
e1 "example1"

还有一种匿名导入包,但是匿名导入的包无法使用,一般这么做是为了加载包下的 init 函数,但又不需要包中的类型,比如说注册数据库驱动

1
2
3
4
5
6
package main

import (
e "example"
_ "mysql-driver"
)

导入包后,可以通过 名称.标识符 去访问,比如

1
2
3
4
5
6
7
8
9
10
package main

import (
"example"
"fmt"
)

func main() {
fmt.Println(example.User)
}

私有类型无法访问,并且 go 不支持循环导入,不管是直接的还是间接的。例如包 A 导入了包 B,包 B 也导入了包 A,这是直接循环导入;包 A 导入了包 C,包 C 导入了包 B,包 B 又导入了包 A,这就是间接的循环导入,存在循环导入的话将会无法通过编译。

内部包

go 中一个包内名为 internal 包为内部包,外部包无法访问内部包

标识符

go 中所有内置关键字

1
2
3
4
5
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

运算符

go 语言中支持的运算符号的优先级排列

1
2
3
4
5
6
Precedence    Operator
5 * / % << >> & &^
4 + - | ^
3 == != < <= > >=
2 &&
1 ||

go 语言中没有选择将~作为取反运算符,而是复用了^符号,当两个数字使用^时,例如a^b,它就是异或运算符,只对一个数字使用时,例如^a,那么它就是取反运算符。go 也支持增强赋值运算符

1
2
3
a += 1
a /= 2
a &^= 2

注意:go 中没有自增和自减,他们变成了语句 statement ,并且规定了只能位于操作数的后方,所以不用再去纠结 i++++i 这种不太聪明的问题,但是没有返回值。甚至 a = b++ 这种写法是错误的。

字面量

整型字面量

允许使用 _ 进行数字划分,但是仅仅允许在前缀符号之后和数字之间使用

1
2
3
4
5
6
7
8
9
10
24 		// 24
024 // 24
2_4 // 24
0_2_4 // 24
10_000 // 10k
100_000 // 100k
0O24 // 20
0b00 // 0
0x00 // 0
0x0_0 // 0

浮点型字面量

通过不同前缀可以表达不同进制浮点数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0.
72.40
072.40 // == 72.40
2.71828
1.e+0
6.67428e-11
1E6
.25
.12345E+5
1_5. // == 15.0
0.15e+0_2 // == 15.0

0x1p-2 // == 0.25
0x2.p10 // == 2048.0
0x1.Fp+0 // == 1.9375
0X.8p-0 // == 0.5
0X_1FFFP-16 // == 0.1249847412109375
0x15e-2 // == 0x15e - 2 (integer subtraction)

复数字面量

1
2
3
4
5
6
7
8
9
10
11
12
0i
0123i // == 123i
0o123i // == 0o123 * 1i == 83i
0xabci // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i // == 0x1p-2 * 1i == 0.25i

字符字面量

字符字面量必须使用单引号括起来 ''

1
2
3
4
5
6
7
8
9
'a'
'ä'
'你'
'\t'
'\007'
'\x07'
'\xff'
'\u12e4'
'\U00101234'

转义字符

1
2
3
4
5
6
7
8
9
10
\a   U+0007 响铃符号
\b U+0008 回退符号
\f U+000C 换页符号
\n U+000A 换行符号
\r U+000D 回车符号
\t U+0009 横向制表符号
\v U+000B 纵向制表符号
\\ U+005C 反斜杠转义
\' U+0027 单引号转义 (该转义仅在字符内有效)
\" U+0022 双引号转义 (该转义仅在字符串内有效)

字符串字面量

字符串字面量必须使用双引号 "" 括起来或者反引号(反引号字符串不允许转义)

1
2
3
4
5
6
7
8
9
`abc`                // "abc"
`\n
\n` // "\\n\n\\n"
"\n"
"\"" // `"`
"kfcvme50!\n"
"疯狂星期四v我50"
"\u65e5本\U00008a9e"
"\xff\u00FF"

函数

通过 func 关键字来进行

1
2
3
func main() {
fmt.Println(1)
}

参数类型后置

1
2
3
func Hello(name string) {
fmt.Println(name)
}

多返回值

1
2
3
func Pos() () (x, y float64) {
...
}

代码风格

花括号换行

go 中花括号都不能换行

1
2
3
4
5
6
7
8
9
10
//正确
func main() {
fmt.Println("Hello butt3rf1y!")
}

//错误
func main()
{
fmt.Println("Hello butt3rf1y!")
}

代码缩进

go 中代码间隔也有一定的意义,比如说

1
1*4 + 5/1*4

在格式化后,* 符号之间的间隔会显得更紧凑,意味着优先进行运算,而 + 符号附近的间隔则较大,代表着较后进行运算。

省略

在 go 中的 if 和 for 语句可以只写一行,但必须加上花括号

1
2
3
4
5
func main() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
}

三元表达式

go 中没有三元表达式,不能写像 c 语言中的 temp = (a > b) ? a : b; 这种表达式。


Re:从零开始的 Go 之旅-基本语法
http://example.com/2025/01/20/基本语法/
作者
butt3rf1y
发布于
2025年1月20日
许可协议