Go 语言是谷歌 2009 发布的第二款开源编程语言。
创建项目
新建文件夹 helloworld
,新建main.go
package main
import "fmt"
func main() {
fmt.Println("Hello world!")
}
然后打开Terminal
# 初始化模块
go mod init helloworld
# 编译并运行
go build && ./helloworld
# output:
Hello world!
go mod
是 Go 语言管理模块依赖的工具,有点类似npm,yarn
变量
Go 语言中的变量和其他语言大同小异:数据类型基本一致,只是关于全局和局部作用域对变量初始化的限制有所不同。
数据类型
- 布尔型(
bool
): 值只可以是常量true
或者false
。 - 数字类型: 整型
int
和浮点型float
,支持复数(业务代码用不到),其中位的运算采用补码。 - 字符串类型(
string
): 使用UTF-8
编码标识Unicode
文本。 - 其他:指针、数组、结构体(
struct
)、联合体 (union
不常用)、函数、切片、接口(interface
)、Map
、Channel
声明变量的方式
你可以直接通过 var 声明、批量声明、语法糖简写
// 各种定义变量方式
func sampleDefineVariable() {
// var identifier type
var name string
name = "s"
//根据赋值自动判断类型
var p = name
//直接声明并赋值(必须是初次声明才有冒号)
p2 := "as"
//多变量声明,不赋值自动赋值为0,比如d e f
var a, b, c = 1, 2, 3
var d, e, f int
h, i, j := 1, 2, 3
//类型不同的多个变量,难看的要死
var (
k int
l string
)
var m, n, o = "a", 1, true
fmt.Println(name + p + p2 + l + m)
fmt.Println(a + b + c + d + e + f + h + i + j + k + n)
fmt.Println(o)
}
注意:已经声明并初始化的变量必须使用,不然编译不通过
全局和局部变量
结论:
全局变量可以不初始化不使用
局部变量必须初始化并使用
不知道为什么会有这种规定
常量
Go 的常量也是和其他语言差不多,多了个亮点:枚举
常量写法:
const identifier [type] = value
常量必须赋初始值!!
批量创建常量并使用iota
递增
func sampleDefineVariable() {
const (
F = iota // 0
G = iota // 1
H = iota // 2
)
fmt.Println(F, G, H) // 0 1 2
}
iota
默认从 0 开始递增,初次看到这个感觉没什么用,来点最佳实践!
const (
_ = iota
KB = 1 << (10 * iota)
MB = 1 << (10 * iota)
GB = 1 << (10 * iota)
TB = 1 << (10 * iota)
PB = 1 << (10 * iota)
)
条件分支
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
// 这里开始就不能使用 v 了
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
Go 语言中的if
第一个位置类似 for
循环的第一个参数,可以执行表达式,声明的变量其作用域仅仅存在代码块中。
循环
我不经常用switch
,原因应该都知道吧
为什么很多程序员不用switch,而是大量的if……else if?-头条问答 (toutiao.com)
我也不经常用while
,golang 中没有 while
而是用 for
代替
Go 只有一种循环结构:for
循环。
基本的 for
循环由三部分组成,它们用分号隔开:
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum) // 45
}
- 初始化语句:在第一次迭代前执行
- 条件表达式:在每次迭代前求值
- 后置语句:在每次迭代的结尾执行
初始化语句通常为一句短变量声明,该变量声明仅在 for
语句的作用域中可见。
一旦条件表达式的布尔值为 false
,循环迭代就会终止。
注意:和 C、Java、JavaScript 之类的语言不同,Go 的 for 语句后面的三个构成部分外没有小括号, 大括号 { }
则是必须的。
和其他语言一样,for
三个位置都是可选的,哈哈哈
推迟语句
defer
会将后面表达式推迟到函数 return
之后执行。
推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
package main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
/*
hello
world
*/
这个有什么用?网络 I/O、文件 I/O 操作之后主动关闭,避免死锁
Go Defer 高级实践 - SegmentFault 思否
结束
第一次接触到了 Go 语言的 defer
,感觉很像 react 中的 useEffect
的 return
,不得不佩服谷歌开发者,能想出这么优雅的处理方式。
参考: