Avatar

本节包括 Go 的基本数据类型、变量与常量、运算符、控制结构、函数等内容。

Part 2 Go 基础语法
1272 words

1 基本数据类型h2

Go 中的基本数据类型只有三种:布尔型、数字类型、字符串类型。

布尔型即truefalse

常用的数字类型有intfloat32float64

字符串型string就是一串固定长度单个字符连接起来的字符序列。

Go 中的数字型

int只是一个别名,在 32 位系统和 64 位系统中分别代表int32int64。除了这两者以外,Go 还有uint8 uint16 uint32 uint64 int8 int16 int32 int64

除此之外,Go 还支持复数类型complex64 complex128

2 变量与常量h2

2.1 变量h3

Go 通常使用var关键字来声明一个变量:

var name string = "YOAKE"
var age int = 23
var isStudent bool = true

你当然也可以不选择初始化。不带初始化声明的变量为零值(数字0、空字符串""false)。

如果你比较懒,不想写类型。Go 会根据初始化时所赋值的类型自动推断该变量的类型。

var name = "YOAKE"
name = 1 // Error: cannot use 1 (untyped int constant) as string value in assignment

不过既然类型能自动推断,那么var关键字就显得有些多余了。因此 Go 有:=操作符:

name := "YOAKE"
age := 23
isStudent := true

现在你应该体会到 Go 的简洁和优雅了。虽然:=操作符很好用,但是它只能在函数体中使用,因此不能使用它来定义全局变量(虽然也不建议在任何时候定义全局变量)。

当然也有多变量声明,出始值会按照顺序依次赋给各个变量:

name, age, isStudent := "YOAKE", 23, true

Go 也提供了多变量赋值功能,你可以像写 Python 那样交换两个变量的值:

a, b := 1, 2
a, b = b, a // a: 2, b: 1

你可能已经发现了,如果你定义了一个变量却没有使用的话,就会报错:

a, b := 1, 2 // declared and not used: a
fmt.Println("b:", b)

这是因为 Go 强制要求你必须使用所有被声明的变量。

2.2 常量h3

常量使用const来声明,你也可以不用写它的类型:

const NAME = "YOAKE"
const AGE = 23
const IS_STUDENT = true

3 运算符h2

Go 的运算符和其他的都大差不差:

  • 算术运算符:+ - * / % ++ --
  • 关系运算符:== != > < >= <=
  • 逻辑运算符:&& || !
  • 位运算符:按位与&、按位或|、按位异或^、左移<<、右移>>
  • 赋值运算符:= += -= *= /= %= <<= >>= &= ^= |=

此外,Go 中是有指针的,因此有指针运算符:

  • *a:指针变量;
  • &a:变量的实际地址。

4 控制结构h2

if-else语句 for循环 switch语句

4.1 if-elseh3

结构和其他语言类似,需要注意的是布尔表达式没有括号:

age := 23
if age < 18 {
fmt.Println("未成年")
} else {
fmt.Println("成人")
}

4.2 switchh3

和其他语言也差不多,不过没有break语句。因此匹配某一分支成功后就不会执行其他(后续)的分支。

score := 85
switch {
case score >= 90:
fmt.Println("Grade: A")
case score >= 80:
fmt.Println("Grade: B")
case score >= 70:
fmt.Println("Grade: C")
case score >= 60:
fmt.Println("Grade: D")
default:
fmt.Println("Grade: F")
}

4.3 forh3

Go 的 for 循环有三种形式,分别是:

  • 传统的 for 循环:
for index := 0; index < 10; index ++ { }
  • while 风格的循环:
index := 0
for index < 10 {
// existing code
index ++
}
  • 死循环:
for {}

和其他现代语言一样,Go 也支持字符串、数组等结构的 for-each 迭代:

numbers := [5]int{1, 2, 3, 4, 5}
for index, num := range numbers{
fmt.Printf("第 %d 位的值为", index, num)
}

5 函数h2

5.1 函数的声明h3

Go 在声明函数时要写明参数类型和返回值类型:

func add(x int, y int) int {
return x + y
}

如果参数都是相同类型,则可以简写:

func add(x, y int) int {
return x + y
}

其实也和其他语言差不多。但是 Go 的函数可以返回多个值,就像 Python 一样:

func addAndMulti(x int, y int) (int, int) {
return x + y, x * y
}

同理,你也要依次写上返回值的类型。

空白标识符_

有时候我们不想使用函数的全部返回值,就可以用_来选择性地丢弃。例如:

addResult, _ = addAndMulti(3, 5)

这样我们就安全地丢弃了我们不想要的第二个返回值。

5.2 匿名函数h3

Go 语言中将函数视为一等公民,这就让匿名函数变得非常好用,就像 TypeScript:

add := func(a, b int) int {
return a + b
}
result := add(1, 2)
别把 Go 当成 TypeScript 来写

你一定和我有一样的想法:那我所有的函数都用匿名函数来写并且赋值就好了,统一、美观。

别这样做。在 Go 中,坚持使用具名函数是绝对的主流。

有了匿名函数,就可以写闭包:

func intSeq() func() int {
i := 0
return func() int {
i++ // 匿名函数引用了外部的 i
return i
}
}
func main() {
nextInt := intSeq() // nextInt 变成了一个闭包
fmt.Println(nextInt()) // 1
fmt.Println(nextInt()) // 2
}

也可以作为回调函数:

func visit(numbers []int, f func(int)) {
for _, n := range numbers {
f(n)
}
}
visit([]int{1, 2, 3}, func(n int) {
fmt.Println(n * n)
})