ctrlcv-dev.comgithub

Gocheatsheet

贡献者:BAI

GO

介绍

Hello world

hello.go

GO
package main
import "fmt"
func main() {
message := greetMe("world")
fmt.Println(message)
}
func greetMe(name string) string {
return "Hello, " + name + "!"
}
BASH
go build

也可以在 Go repl,或 A Tour of Go. 做实验

变量

变量声明

GO
var msg string
msg = "Hello"

缩写(推断类型)

GO
msg := "Hello"

常量

GO
const Phi = 1.618

常量可以是字符、字符串、布尔值或数字类型

详见: Constants

基本类型

字符串

GO
str := "Hello"
GO
str := `Multiline
string`

数字

基本的数字类型

GO
num := 3 // int
num := 3. // float64
num := 3 + 4i // complex128
num := byte('a') // byte (alias for uint8)

其他类型

GO
var u uint = 7 // uint (无符号)
var p float32 = 22.7 // 32-bit float

数组

GO
// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

数组需要一个固定的尺寸

Slice

GO
slice := []int{2, 3, 4}
GO
slice := []byte("Hello")

Slice 类型可以有动态的尺寸

指针

GO
func main () {
b := *getPointer()
fmt.Println("Value is", b)
}
GO
func getPointer () (myPointer *int) {
a := 234
return &a
}
GO
a := new(int)
*a = 234

指针指向一个变量的内存所在的位置,Go 是一种完全的垃圾回收机制的语言。 Pointers point to a memory location of a variable. Go is fully garbage-collected.

详见: 指针

类型转换

GO
i := 2
f := float64(i)
u := uint(i)

详见: 类型转换

控制流

条件语句

GO
if day == "sunday" || day == "saturday" {
rest()
} else if day == "monday" && isTired() {
groan()
} else {
work()
}

详 f: If

if 条件中的语句

GO
if _, err := doThing(); err != nil {
fmt.Println("Uh oh")
}

if 语句中可以执行一系列其他带 ; 的语句。生命的变量仅在 if 这个作用域内生效

详见: If with a short statement

Switch 语句

GO
switch day {
case "sunday":
// case 语句不会向下vixy
fallthrough
case "saturday":
rest()
default:
work()
}

详见: Switch

For 循环

GO
for count := 0; count <= 10; count++ {
fmt.Println("My counter is at", count)
}

详见: For 循环

For-Range 循环

GO
entry := []string{"Jack","John","Jones"}
for i, val := range entry {
fmt.Printf("At position %d, the character %s is present\n", i, val)
}

详见: For-Range 循环

While 循环

GO
n := 0
x := 42
for n != x {
n := guess()
}

详见: Go 的 "while"

函数

Lambda

GO
myfunc := func() bool {
return x > 10000
}

函数是第一个类对象

多类型返回

GO
a, b := getMessage()
GO
func getMessage() (a string, b string) {
return "Hello", "World"
}

带命名的返回值

GO
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}

详见: Named return values

导入

GO
import "fmt"
import "math/rand"
GO
import (
"fmt" // gives fmt.Println
"math/rand" // gives rand.Intn
)

上面两者等效

详见: Importing

别名

GO
import r "math/rand"
GO
r.Intn()

导出命名

GO
func Hello () {
···
}

导出的名称需要大写开头

详见: Exported names

GO
package hello

Every package file has to start with package.

并发

Goroutines

GO
func main() {
// 一个 Channel
ch := make(chan string)
// 开始并发
go push("Moe", ch)
go push("Larry", ch)
go push("Curly", ch)
// 读取 3 个结果
// 因为goroutines 是并发的,所以顺序不固定
fmt.Println(<-ch, <-ch, <-ch)
}
GO
func push(name string, ch chan string) {
msg := "Hey, " + name
ch <- msg
}

Channel 是并发安全的通讯对象,可以在 goroutines 中 使用

详见: Goroutines, Channels

带缓存的 Channel

GO
ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

带缓存的 Channel 限制了可以保存的消息的数量

详见: Buffered channels

关闭 Channel

关闭一个 Channel

GO
ch <- 1
ch <- 2
ch <- 3
close(ch)

迭代 Channel 直到频道关闭

GO
for i := range ch {
···
}

如果 ok === false 则关闭

GO
v, ok := <- ch

详见: Range and close

WaitGroup

GO
import "sync"
func main() {
var wg sync.WaitGroup
for _, item := range itemList {
// 增加 WaitGroup 计数器
wg.Add(1)
go doOperation(item)
}
// 等待 goroutines 完成
wg.Wait()
}
GO
func doOperation(item string) {
defer wg.Done()
// do operation on item
// ...
}

一个 WaitGroup 会等待一组 goroutines 执行完毕。主 goroutines 执行时会添加其他需要等待的 goroutines。 goroutines 执行 wg.Done() 时结束

详见: WaitGroup

错误控制

Defer

GO
func main() {
defer fmt.Println("Done")
fmt.Println("Working...")
}

Defer 可以执行一个函数,直到被包裹的函数返回,其参数会直接计算,但函数调用不会直接执行

详见: Defer, panic and recover

Defer 函数

GO
func main() {
defer func() {
fmt.Println("Done")
}()
fmt.Println("Working...")
}

Lambda 操作符更适合 defer 块

GO
func main() {
var d = int64(0)
defer func(d *int64) {
fmt.Printf("& %v Unix Sec\n", *d)
}(&d)
fmt.Print("Done ")
d = time.Now().Unix()
}

除非我们用一个指针去在在 main 函数的末尾去取值,不然 Defer 函数会使用当前 d 的值,

结构体

定义

GO
type Vertex struct {
X int
Y int
}
GO
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X, v.Y)
}

详见: Structs

语法

GO
v := Vertex{X: 1, Y: 2}
GO
// 字段名可省略
v := Vertex{1, 2}
GO
// Y 是隐式的
v := Vertex{X: 1}

你也可以设置字段名

结构体指针

GO
v := &Vertex{1, 2}
v.X = 2

v 是指针时。v.X(*v).X 一样;

方法

Receiver

GO
type Vertex struct {
X, Y float64
}
GO
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
GO
v := Vertex{1, 2}
v.Abs()

上面这些不是类,但是你可以用 receivers 定义方法

详见: Methods

Mutation

GO
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
GO
v := Vertex{6, 12}
v.Scale(0.5)
// `v` is updated

通过将你的 receiver 定义为一个指针,你可以直接修改其中的值。

详见: Pointer receivers

接口

基本接口

GO
type Shape interface {
Area() float64
Perimeter() float64
}

结构

GO
type Rectangle struct {
Length, Width float64
}

Rectangle 结构通过实现了 Shape 的全部方法隐式实现了 Shape 接口

方法

GO
func (r Rectangle) Area() float64 {
return r.Length * r.Width
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Length + r.Width)
}

这些方法定义在 Shape中,并在 Rectangle 中实现。

接口示例

GO
func main() {
var r Shape = Rectangle{Length: 3, Width: 4}
fmt.Printf("Type of r: %T, Area: %v, Perimeter: %v.", r, r.Area(), r.Perimeter())
}

参考

官方资料

其他链接