这次我们邀请了 Go 同学,欢迎他来为我们答疑解惑。
Go同学:
大家好,我叫Go,一个开源的编程语言,能够让软件变得构造简单且高效。
Go同学:
简洁、快速、安全
并行、有趣、开源
内存管理、数组安全、编译迅速
Go同学:
搭载 Web 服务器,存储集群或类似用途的巨型中央服务器。
提供了海量并行的支持,适合游戏服务端的开发
Go同学:
只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的
goroutine 语法格式:
go 函数名( 参数列表 )
例如:
go f(x, y, z)
Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。同一个程序中的所有 goroutine 共享同一个地址空间。
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("test")
say("hello")
}
执行以上代码,输出的 hello 和 world 是没有固定先后顺序。因为它们是两个 goroutine 在执行:
test
test
hello
hello
test
hello
hello
test
test
hello
Go同学:
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <-
用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
ch <- v // 把 v 发送到通道 ch
v := <-ch // 从 ch 接收数据
// 并把值赋给 v
声明一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:
ch := make(chan int)
注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。
以下实例通过两个 goroutine 来计算数字的平方-5,在 goroutine 完成计算后,它会计算两个结果的和:
package main
import "fmt"
func square(s int, c chan int) {
result := s * s - 5
c <- result // 把 result 发送到通道 c
}
func main() {
c := make(chan int)
go square(3, c)
go square(4, c)
x, y := <-c, <-c // 从通道 c 中接收
fmt.Println(x, y, x+y)
}
输出结果为:
4 11 15
通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:
ch := make(chan int, 100)
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。
由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。
注意:如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。
package main
import "fmt"
func main() {
// 这里我们定义了一个可以存储整数类型的带缓冲通道
// 缓冲区大小为3
ch := make(chan int, 3)
// 因为 ch 是带缓冲的通道,我们可以同时发送3个数据
// 而不用立刻需要去同步读取数据
ch <- 100
ch <- 200
ch <- 300
// 获取这两个数据
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
输出结果
100
200
300
Go 通过 range 关键字来实现遍历读取到的数据
package main
import (
"fmt"
)
func square(n int, c chan int) {
for i := 1; i <= n; i++ {
x := i * i
c <- x
}
close(c)
}
func main() {
c := make(chan int, 5)
go square(5, c)
// range 函数遍历每个从通道接收到的数据,因为 c 在发送完 5 个
// 数据之后就关闭了通道,所以这里我们 range 函数在接收到 5 个数据
// 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数会报死锁的错误提示。
for i := range c {
fmt.Println(i)
}
}
输出结果:
1
4
9
16
25
通道不关闭,造成死锁的错误提示:
1
4
9
16
25
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/box/main.go:23 +0xf1
Exited with error status 2
Go同学:
我支持的系统:Linux、FreeBSD、Mac OS、Windows。
安装包下载地址为:https://golang.org/dl/。
安装步骤去上面说的网站看下就知道啦
Go同学:
由多个标记组成,可以是关键字,标识符,常量,字符串,符号。
在 Go 程序中,一行代表一个语句结束,不需要分号。
注释不会被编译,每一个包应该有相关注释。
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
Go 语言的字符串可以通过 + 实现
Go 代码中会使用到25 个关键字或保留字
Go 语言中变量的声明必须使用空格隔开
Go同学:
布尔型
常量 true 或者 false
数字类型
uint8、uint16、uint32**、uint64、int8、int16、int32、int64、float32、float64、 complex64、**complex128
字符串类型:
派生类型:
(a) 指针类型(Pointer)
(b) 数组类型
(c) 结构化类型(struct)
(d) Channel 类型
(e) 函数类型
(f) 切片类型
(g) 接口类型(interface)
(h) Map 类型
Go同学:
声明变量的一般形式是使用 var 关键字
第一种,指定变量类型,如果没有初始化,则变量默认为零值。
第二种,根据值自行判定变量类型。
第三种,省略 var, 注意 *:=* 左侧如果没有声明新的变量,就产生编译错误
Go同学:
const identifier [type] = value,略类型说明符 [type],因为编译器可以根据变量的值来推断其类型
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型
Go同学:
算术运算符
关系运算符
逻辑运算符
位运算符
赋值运算符
其他运算符
Go同学:if,if else,swith,select
Go同学:我有for 循环,可以用break/continue/goto语句
Go同学:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
func:函数由 func 开始声明
function_name:函数名称,函数名和参数列表一起构成了函数签名。
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
函数体:函数定义的代码集合。
Go同学:
函数内定义的变量称为局部变量
函数外定义的变量称为全局变量
函数定义中的变量称为形式参数
Go同学:
Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:
var variable_name [SIZE] variable_type
Go语言初始化数组:
var test = [5] float32{200.0, 2.0, 3.14, 20.0, 100.0}
可以通过索引获取/设置数组中的值:
test[4]
test[2] = 100
Go同学:
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
error类型是一个接口类型,这是它的定义:
type error interface {
Error() string
}
我们可以在编码中通过实现 error 接口类型来生成错误信息。
函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
Go同学:
IDEA
IntelliJ idea是非常强大的一款IDE,支持丰富的插件。需要安装两个插件Go和File Watcher
GoLand
GoLand 是 Jetbrains 家族的 Go 语言 IDE,有 30 天的免费试用期。
LiteIDE
LiteIDE 是一款开源、跨平台的轻量级 Go 语言集成开发环境(IDE)
Eclipse