该文内容整理自Go指南
基本结构
若变量名以大写字母开头则为导出的, 函数外的每个语句都必须以关键词(var, func…)开始
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello world")
}
函数
func swap(x, y string) (string, string) {
return y, x
}
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
//函数值
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
hypot := func(x, y float64) float64 {
return x*x + y*y
}
//函数闭包, 即引用了函数体之外变量的函数值
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
pos, neg := adder(), adder()
// defer语句会将函数推迟到外层函数返回之后执行
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
变量/常量/指针
var i, j int = 1, 2
var c, python = true, "no"
k := 3 // 仅能在函数内使用
const Pi = 3.14
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
)
i = 42
p := &i
*p = 21
循环与分支
// Go仅有for循环
for i := 0; i < 10; i++ {
}
for ; sum < 1000; {
}
for sum < 1000 {
}
// 无限循环
for {
}
// 与for一样,if可以在条件表达式之前执行一个简单的语句
if v := math.Pow(x, n); v < lim {
} else {
}
switch os := runtime.GOOS; os {
case "darwin":
// ...
case "linux":
// ...
default:
// ...
}
结构体
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
v := Vertex{1, 2}
p := &v
p.X = 1e9 //自动转换为(*p).X
v2 = &Vertex{2, 3} //创建并返回指针
}
数组
var a [2]string
primes := [6]int {1,2,3,4,5,6}
var s []int = primes[1 : 4] //半开区间, 且为引用
q := []int {1,2,3}
s := []struct {
i int
} {
{1},
{2}
}
len(a) //获取数组长度
cap(a) //获取数组容量
a := make([]int, 5) //len(a)=5, cap(a)=5
b := make([]int, 0, 5) //len(a)=0, cap(a)=5
board := [][]string {
[]string{"_", "_"},
[]string{" ", "_"}
}
board[0][0] = "X"
var s []int
s = append(s, 1,2,3,4)
// for range 第一个值为下标,第二个值为元素的副本, 可以用_替代
for i, v := range s {
fmt.Printf(i, v)
}
映射
var m map[string]Vertex
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex {
40, -74
}
var c = map[string]Vertex {
"Bell Labs": Vertex {
40, -74
},
"Google": Vertex {
37, -122
}
}
delete(m, "Google")
v, ok := m["Google"] // 不存在此键则ok为false, v为零值
方法
func (v Vertex) Abs() float64 {
return v.X * v.X + v.Y * v.Y
}
v := Vertex{3, 4}
v.Abs()
// 可以为非结构体类型声明方法
type MyFloat float64
func (f MyFloat) Abs() float64 {
//...
}
f := MyFloat(2)
f.Abs()
// 指针接收者能够更改接收者指向的指,值接收者则是对副本进行操作
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
接口
type Abser interface {
Abs() float64
}
//接口类型的变量可以保存任何实现了这些方法的值
var a Abser
// 类型通过实现一个接口的所有方法来实现该接口,
// 因此无需专门显示声明,也就没有implements关键字
type I interface {
M()
}
type T struct {
S string
}
func (t T) M() {
//...
}
func main() {
var i I = T{"hello"}
i.M()
}
// 空接口能够保存任何类型的值,因为每个类型都至少实现了零个方法
var i interface{}
i = 42
i = "hello"
// fmt包中定义的Stringer是最普遍的接口之一
type Stringer interface {
String() string
}
func (p Person) String() string {
//...
}
a := Person {42}
fmt.Println(a)
类型断言
var i interface {} = "hello"
s, ok := i.(string) //断言接口值i保存了具体类型string, 并将值赋予变量s, 同时由ok判断是否断言成功
f := i.(float64) // 将产生panic
类型选择
// 与类型断言相似,但具体类型被替换成了关键字type
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
错误
// Go使用error值来表示错误状态, 且error是一个内建接口
type error interface {
Error() string
}
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
Goroutine
go f(x, y, z) //启动一个新的goroutine
// 信道通过 <- 来发送或接收值
// 默认情况下,发送和接收操作在另一端准备好之前
// 都会阻塞,因此goroutine可以在没有显示的锁情况下进行同步
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将和送入 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从 c 中接收
fmt.Println(x, y, x+y)
}
// 信道可以带缓冲,仅当信道的缓冲区填满后,
// 向其发送数据时才会阻塞,当缓冲区为空时,
// 接收方会阻塞
ch := make(chan int, 2)
// 发送者可以通过close关闭一个信道来表示没有需要发送的值了
// 接收者可以测试信道是否被关闭
// 若没有值可以接收且信道已被关闭,则ok为false
v, ok := <-ch
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
// 不断从信道接收值,直到c被关闭
for i := range c {
fmt.Println(i)
}
}
// 只有发送者才能关闭信道,同时信道在通常情况下无需关闭,
// 只有在必须告诉接收者不再有需要发送的值时才有必要关闭,
// 例如终止range循环
// select语句使得一个goroutine能够等待多个通信操作
// 阻塞到某个分支可以继续执行为止,当多个分支都准备
// 好时会随机选择一个执行。同时当其他分支都没准备好,
// default分支就会执行
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
default:
//...
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
sync.Mutex
import (
"fmt"
"sync"
"time"
)
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
c.v[key]++
c.mux.Unlock()
}
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}
Comment