一 语句分隔方式
不同于C或Java,在Go中,一行代表一个语句的结束,不需要我们额外使用分号作为一行代码的结尾,Go编译器会自动根据行的划分来划分语句。但是如果我们将多个语句写在同一行中,那么必须使用;进行人为的区分,但是在实际开发中我们应该尽量避免这种不规范的写法。
例如在我们上一篇书写的示例代码中,我们并没有使用;进行语句的划分,但是程序可以正常编译运行,并没有报错。
package main // 定义包名
import "fmt" // 导包
func main() {
/* 这是我的第一个程序 */
fmt.Println("Hello, World!")
}
二 标识符和注释
Go中的标识符和注释并无特别之处,在Go语言中,标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
例如以下几个标识符就是不合法的标识符:
- 1ab(以数字开头)
- case(Go 语言的关键字)
- a+b(运算符是不允许的)
注释我们在上一篇的示例代码中也已经使用过了,有单行注释和多号注释两种,分别用// 开头和以 /* 开头,以 */ 结尾。
三 字符串连接
在Go语言中,我们可以直接使用“+”来连接两个字符串,例如:
四 关键字
Go语言中,一共有25个关键字或保留字,分别为:
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 语言还有 36 个预定义标识符:
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 |
五 常用数据类型
1.布尔型:bool。其值只可以是常量 true 或者 false
var b bool = true
2.整型:byte,int,int8, int16,int32,int64,uint,uint8,uint16,uint32,uint64,uintptr
3.浮点型:float32,float64
4.复数类型:complex64,complex128
5.字符型:rune
6.字符串:string
7.错误类型:error
六 变量声明
Go语言中有4种常用的变量声明方式:
1.指定变量类型,如果没有初始化,则变量默认为零值(零值为变量没有做初始化时系统默认设置的值,不一定是0。例如数值类型默认为0,布尔类型默认为false,字符串类型默认为“”)。
var a int
2.正常声明
var d int = 100
3. 不指定变量类型,根据值自行判定变量类型。
var b = "true"
4.省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误。
c := 100
/* 这条语句相当于
var c int
c =1 */
!注意:
这种声明方式声明的变量只能被用在函数体内,而不可以用于全局变量的声明与赋值;此外=左侧的变量不应该是已经声明过的,因为:=是初始化+赋值的过程,我们如果想要更改一个已声明变量的值,直接使用=赋值就可以。
5.多变量声明方式
//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
// 和 python 很像,不需要显示声明类型,自动推断
var vname1, vname2, vname3 = v1, v2, v3
// 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
vname1, vname2, vname3 := v1, v2, v3
// 这种因式分解关键字的写法一般用于声明全局变量
var (
vname1 v_type1
vname2 v_type2
)
6.空白标识符 _ :用于抛弃值,变量 _ 不具备读特性( Go 语言中必须使用所有被声明的变量,但有时并不需要使用从一个函数得到的所有返回值,此时就可以用到空白标识符)
_, value := 7, 5
// fmt.Println(_) 该行语句会报错,因为_变量不可读
fmt.Println(value)
7.全局变量是允许声明但不使用,但非全局变量仅仅声明且赋值也会报错,我们必须使用这个值
七 常量及常量声明
Go语言中的常量是一个简单值的标识符,也就是在程序运行时,不会被修改的量。常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。我们可以使用const关键字来声明一个常量。
const identifier [type] = value
const c_name1, c_name2 = value1, value2
const a = "abc"
const b int = 4
fmt.Println("a = ", a)
fmt.Println("b = ", b)
八 使用常量作为枚举
我们可以使用const关键字来进行枚举,语法格式如:
const (
BEIJING = 0
GUANGZHOU = 1
SHANGHAI = 2
)
在Go语言中,还有一个iota关键字,它只能在const关键字中使用,其初始值为0,会在const中每新增一行常量声明,将使 iota 计数一次(可理解为 const 语句块中的行索引)。例如上面的枚举语句,我们就可以改写成:
const (
BEIJING = iota
GUANGZHOU
SHANGHAI
)
但是iota是随着行的增加而增加的,并不跟随变量的数目改变,例如这个例子:
const (
a, b = iota + 1, iota + 2
c, d
e, f = iota * 2, iota * 3
g = "123"
h
i = iota
)
当我们运行程序打印输出它们的值时,可以得到下面的结果:
代码分析如下:
九 运算符
1.算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
-- | 自减 | A-- 输出结果 9 |
2.关系运算符
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
3.逻辑运算符
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 | (A && B) 为 False |
|| | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 | (A || B) 为 True |
! | 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 | !(A && B) 为 True |
4.位运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 | (A & B) 结果为 12, 二进制为 0000 1100 |
| | 按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或 | (A | B) 结果为 61, 二进制为 0011 1101 |
^ | 按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 | (A ^ B) 结果为 49, 二进制为 0011 0001 |
<< | 左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
5.赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C = A + B 将 A + B 表达式结果赋值给 C |
+= | 相加后再赋值 | C += A 等于 C = C + A |
-= | 相减后再赋值 | C -= A 等于 C = C - A |
*= | 相乘后再赋值 | C *= A 等于 C = C * A |
/= | 相除后再赋值 | C /= A 等于 C = C / A |
%= | 求余后再赋值 | C %= A 等于 C = C % A |
<<= | 左移后赋值 | C <<= 2 等于 C = C << 2 |
>>= | 右移后赋值 | C >>= 2 等于 C = C >> 2 |
&= | 按位与后赋值 | C &= 2 等于 C = C & 2 |
^= | 按位异或后赋值 | C ^= 2 等于 C = C ^ 2 |
|= | 按位或后赋值 | C |= 2 等于 C = C | 2 |
6.指针相关
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a; 将给出变量的实际地址。 |
* | 指针变量。 | *a; 是一个指针变量 |
十 条件语句
Go语言中不支持三目运算符。
语句 | 描述 |
---|---|
if 语句 | if 语句 由一个布尔表达式后紧跟一个或多个语句组成。 |
if...else 语句 | if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。 |
if 嵌套语句 | 你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。 |
switch 语句 | switch 语句用于基于不同条件执行不同动作。 |
select 语句 | select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 |
select语句语法格式如下:
select {
case <- channel1:
// 执行的代码
case value := <- channel2:
// 执行的代码
case channel3 <- value:
// 执行的代码
// 你可以定义任意数量的 case
default:
// 所有通道都没有准备好,执行的代码
}
例如:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
十一 循环语句
for循环的语法格式与C一样:
for i := 0; i <= 10; i++ {
sum += i
}
我们也可以使用For-each range 循环对字符串、数组、切片等进行迭代输出元素。
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
我们可以有选择性的省略key或value:
map1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
map1[3] = 3.0
map1[4] = 4.0
// 读取 key 和 value
for key, value := range map1 {
fmt.Printf("key is: %d - value is: %f\n", key, value)
}
// 读取 key
for key := range map1 {
fmt.Printf("key is: %d\n", key)
}
// 读取 value
for _, value := range map1 {
fmt.Printf("value is: %f\n", value)
}
此外,Go语言也支持循环嵌套,和break、continue等流程控制关键字
// 在for循环中使用break
for i := 0; i < 10; i++ {
if i == 5 {
break // 当 i 等于 5 时跳出循环
}
fmt.Println(i)
}
// 在switch中使用break
func main() {
day := "Tuesday"
switch day {
case "Monday":
fmt.Println("It's Monday.")
case "Tuesday":
fmt.Println("It's Tuesday.")
break // 跳出 switch 语句
case "Wednesday":
fmt.Println("It's Wednesday.")
}
}
在 Go 语言中,break 语句在 select 语句中的应用是相对特殊的。由于 select 语句的特性,break 语句并不能直接用于跳出 select 语句本身,因为 select 语句是非阻塞的,它会一直等待所有的通信操作都准备就绪。如果需要提前结束 select 语句的执行,可以使用 return 或者 goto 语句来达到相同的效果。
// 在 select 语句中使用 break
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(2 * time.Second)
ch1 <- 1
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- 2
}()
select {
case <-ch1:
fmt.Println("Received from ch1.")
case <-ch2:
fmt.Println("Received from ch2.")
break // 跳出 select 语句
}
}
// continue
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* for 循环 */
for a < 20 {
if a == 15 {
/* 跳过此次循环 */
a = a + 1;
continue;
}
fmt.Printf("a 的值为 : %d\n", a);
a++;
}
}