Last active
November 30, 2016 02:22
-
-
Save fuyufjh/b612c4ea000c943cc9adfc98533a37c8 to your computer and use it in GitHub Desktop.
Golang Cheatsheet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Basic function | |
package main | |
import "fmt" | |
func add(x, y int) int { | |
return x + y | |
} | |
func main() { | |
fmt.Println(add(42, 13)) | |
} | |
// Multivalue Return | |
func swap(x, y string) (string, string) { | |
return y, x | |
} | |
// Named returns | |
func split(sum int) (x, y int) { | |
x = sum * 4 / 9 | |
y = sum - x | |
return | |
} | |
// Variables | |
var c, python, java bool // package scope | |
func main() { | |
var i int // function scope | |
} | |
// Variable initialize | |
var i, j int = 1, 2 | |
var c, java = true, "no!" // extract type from initial value | |
python := false | |
// Basic types | |
bool | |
string | |
int int8 int16 int32 int64 | |
uint uint8 uint16 uint32 uint64 uintptr | |
byte // == uint8 | |
rune // == int32 表示一个 Unicode 码点 | |
float32 float64 | |
complex64 complex128 | |
// Define in batch | |
var ( | |
ToBe bool = false | |
MaxInt uint64 = 1<<64 - 1 | |
z complex128 = cmplx.Sqrt(-5 + 12i) | |
) | |
const f = "%T(%v)\n" | |
// Zero value | |
没有明确初始值的变量声明会被赋予它们的 零值 。 | |
零值是: | |
• 数值类型为 0 , | |
• 布尔类型为 false , | |
• 字符串为 "" (空字符串)。 | |
// Constants | |
const Pi = 3.14 | |
const ( | |
Big = 1 << 100 | |
Small = Big >> 99 | |
) | |
// similar to #define rather than const x = 123 | |
// Loop (only for loop in Go) | |
func main() { | |
sum := 0 | |
for i := 0; i < 10; i++ { | |
sum += i | |
} | |
} | |
func main() { | |
sum := 1 | |
for sum < 1000 { // equals to "for ; sum < 1000;" | |
sum += sum | |
} | |
} | |
// If statement | |
func sqrt(x float64) string { | |
if x < 0 { | |
return sqrt(-x) + "i" | |
} | |
return fmt.Sprint(math.Sqrt(x)) | |
} | |
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 | |
} | |
// Switch Statement | |
func main() { | |
fmt.Print("Go runs on ") | |
switch os := runtime.GOOS; os { // 2 subclauses | |
case "darwin": | |
fmt.Println("OS X.") | |
case "linux": | |
fmt.Println("Linux.") | |
default: | |
// freebsd, openbsd, | |
// plan9, windows... | |
fmt.Printf("%s.", os) | |
} | |
} | |
除非以 fallthrough 语句结束,否则分支会自动终止。 | |
switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。 | |
// Defer | |
func main() { | |
defer fmt.Println("world") | |
fmt.Println("hello") | |
} | |
推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。 | |
// Pointer | |
func main() { | |
i, j := 42, 2701 | |
p := &i // point to i | |
fmt.Println(*p) // read i through the pointer | |
*p = 21 // set i through the pointer | |
fmt.Println(i) // see the new value of i | |
p = &j // point to j | |
*p = *p / 37 // divide j through the pointer | |
fmt.Println(j) // see the new value of j | |
} | |
与 C 不同,Go 没有指针运算。 | |
// Struct | |
type Vertex struct { | |
X, Y int | |
} | |
var ( | |
v1 = Vertex{1, 2} // has type Vertex | |
v2 = Vertex{X: 1} // Y:0 is implicit | |
v3 = Vertex{} // X:0 and Y:0 | |
p = &Vertex{1, 2} // has type *Vertex | |
) | |
func main() { | |
fmt.Println(Vertex{1, 2}) | |
v.X = 4 | |
fmt.Println(v.X) | |
p := &v // pointer to struct | |
p.X = 1e9 // same with "->" in C | |
} | |
// Arrays | |
func main() { | |
var a [2]string | |
a[0] = "Hello" | |
a[1] = "World" | |
fmt.Println(a[0], a[1]) | |
fmt.Println(a) | |
primes := [6]int{2, 3, 5, 7, 11, 13} | |
fmt.Println(primes) | |
} | |
// Slices | |
func main() { | |
primes := [6]int{2, 3, 5, 7, 11, 13} | |
var s []int = primes[1:4] | |
fmt.Println(s) | |
} | |
每个数组的大小都是固定的。 而切片则为数组元素提供动态大小的、灵活的视角。 在实践中,切片比数组更常用。 | |
切片并不存储任何数据, 它只是描述了底层数组中的一段。更改切片的元素会修改其底层数组中对应的元素。 | |
r := []bool{true, false, true, true, false, true} //下面这样则会创建一个数组,然后构建一个引用了它的切片 | |
// Create Slice with Make statement | |
x := make([]int, 0, 5) | |
fmt.Printf("len=%d cap=%d %v\n", len(x), cap(x), x) | |
//b len=0 cap=5 [] | |
// Append elements to slice | |
var s []int // nil [] | |
s = append(s, 1) // allocate [1] | |
s = append(s, 2, 3, 4) // reallocate because cap(s) < len(s) + 3 : [1,2,3,4] | |
// Range | |
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} | |
func main() { | |
for i, v := range pow { | |
fmt.Printf("2**%d = %d\n", i, v) | |
} | |
for _, value := range pow { // if not need index | |
fmt.Printf("%d\n", value) | |
} | |
} | |
// Maps | |
m = make(map[string]Vertex) | |
m["Bell Labs"] = Vertex{ | |
40.68433, -74.39967, | |
} | |
fmt.Println(m["Bell Labs"]) | |
映射的零值为 nil 。`nil` 映射既没有键,也不能添加键。 | |
type Vertex struct { | |
Lat, Long float64 | |
} | |
var m = map[string]Vertex{ | |
"Bell Labs": {40.68433, -74.39967}, | |
"Google": {37.42202, -122.08408}, | |
} | |
// Modify Maps | |
m := make(map[string]int) | |
m["Answer"] = 42 // create | |
fmt.Println("The value:", m["Answer"]) | |
m["Answer"] = 48 // update | |
fmt.Println("The value:", m["Answer"]) | |
delete(m, "Answer") // remove | |
fmt.Println("The value:", m["Answer"]) | |
v, ok := m["Answer"] // get value and check | |
fmt.Println("The value:", v, "Present?", ok) | |
// Function values | |
func compute(fn func(float64, float64) float64) float64 { | |
return fn(3, 4) | |
} | |
func main() { | |
hypot := func(x, y float64) float64 { | |
return math.Sqrt(x*x + y*y) | |
} | |
fmt.Println(hypot(5, 12)) | |
fmt.Println(compute(hypot)) | |
fmt.Println(compute(math.Pow)) | |
} | |
// Method | |
type MyFloat float64 | |
func (f MyFloat) Abs() float64 { | |
if f < 0 { | |
return float64(-f) | |
} | |
return float64(f) | |
} | |
func main() { | |
f := MyFloat(-math.Sqrt2) | |
fmt.Println(f.Abs()) | |
} | |
// Pointer recevier | |
func (v Vertex) Abs() float64 { | |
return math.Sqrt(v.X*v.X + v.Y*v.Y) | |
} | |
func (v *Vertex) Scale(f float64) { | |
v.X = v.X * f | |
v.Y = v.Y * f | |
} | |
// Interface | |
type I interface { | |
M() | |
} | |
type T struct { | |
S string | |
} | |
func (t *T) M() { | |
if t == nil { // t can be nil | |
fmt.Println("<nil>") | |
return | |
} | |
fmt.Println(t.S) | |
} | |
func main() { | |
var i I | |
var t *T | |
i = t | |
describe(i) | |
i.M() | |
i = &T{"hello"} | |
describe(i) | |
i.M() | |
} | |
func describe(i I) { | |
fmt.Printf("(%v, %T)\n", i, i) | |
} | |
// Empty Interface | |
func main() { | |
var i interface{} | |
describe(i) | |
i = 42 | |
describe(i) | |
i = "hello" | |
describe(i) | |
} | |
func describe(i interface{}) { | |
fmt.Printf("(%v, %T)\n", i, i) | |
} | |
// Type Assertion | |
s := i.(string) | |
s, ok := i.(string) | |
// Type Switch | |
switch v := i.(type) { // only in switch statement | |
case T: | |
// v 的类型为 T | |
case S: | |
// v 的类型为 S | |
default: | |
// 没有匹配,v 与 i 的类型相同 | |
} | |
// interface Stringer | |
type Person struct { | |
Name string | |
Age int | |
} | |
func (p Person) String() string { | |
return fmt.Sprintf("%v (%v years)", p.Name, p.Age) | |
} | |
// Error (interface) | |
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) | |
} | |
} | |
// Reader (interface) | |
func main() { | |
r := strings.NewReader("Hello, Reader!") | |
b := make([]byte, 8) | |
for { | |
n, err := r.Read(b) | |
fmt.Printf("n = %v err = %v b = %v\n", n, err, b) | |
fmt.Printf("b[:n] = %q\n", b[:n]) | |
if err == io.EOF { | |
break | |
} | |
} | |
} | |
io.Reader 接口有一个 Read 方法: | |
func (T) Read(b []byte) (n int, err error) | |
// Go Routine | |
func main() { | |
go say("world") | |
say("hello") | |
} | |
// Channel | |
ch := make(chan int) | |
ch <- 2 | |
fmt.Println(<-ch) | |
// Channel with buffer | |
ch := make(chan int, 2) | |
ch <- 1 | |
ch <- 2 | |
fmt.Println(<-ch) | |
fmt.Println(<-ch) | |
// range and close for channel | |
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) | |
for i := range c { | |
fmt.Println(i) | |
} | |
} | |
信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有值需要发送的时候才有必要关闭,例如终止一个 range 循环。 | |
// select statement | |
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: | |
fmt.Print(".") | |
time.Sleep(100 * time.Millisecond) | |
} | |
} | |
} | |
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) | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"crypto/md5" | |
"os" | |
"sort" | |
"path/filepath" | |
"errors" | |
"io/ioutil" | |
"sync" | |
) | |
type result struct { | |
path string | |
sum [md5.Size]byte | |
err error | |
} | |
func main() { | |
m, err := MD5All(os.Args[1]) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
var paths []string | |
for path := range m { | |
paths = append(paths, path) | |
} | |
sort.Strings(paths) | |
for _, path := range paths { | |
fmt.Printf("%x %s\n", m[path], path) | |
} | |
} | |
func walkFiles(done <-chan struct{}, root string) (<-chan string, <-chan error) { | |
paths := make(chan string) | |
errc := make(chan error, 1) | |
go func() { | |
defer close(paths) | |
errc <- filepath.Walk(root, func(path string, info os.FileInfo, err error) error { | |
if err != nil { | |
return err | |
} | |
if !info.Mode().IsRegular() { | |
return nil | |
} | |
select { | |
case paths <- path: | |
case <- done: | |
return errors.New("walk canceled") | |
} | |
return nil | |
}) | |
}() | |
return paths, errc | |
} | |
func digester(done <-chan struct{}, paths <-chan string, c chan<- result) { | |
for path := range paths { | |
date, err := ioutil.ReadFile(path) | |
select { | |
case c <- result{path, md5.Sum(date), err}: | |
case <- done: | |
return | |
} | |
} | |
} | |
func MD5All(root string) (map[string][md5.Size]byte, error) { | |
done := make(chan struct{}) | |
defer close(done) | |
paths, errc := walkFiles(done, root) | |
c := make(chan result) | |
var wg sync.WaitGroup | |
wg.Add(10) | |
for i := 0; i < 10; i++ { | |
go func() { | |
digester(done, paths, c) | |
wg.Done() | |
}() | |
} | |
go func() { | |
wg.Wait() | |
close(c) | |
}() | |
m := make(map[string][md5.Size]byte) | |
for r := range c { | |
if r.err != nil { | |
return nil, r.err | |
} | |
m[r.path] = r.sum | |
} | |
if err := <-errc; err != nil { | |
return nil, err | |
} | |
return m, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func gen(nums ...int) <-chan int { | |
out := make(chan int) | |
go func() { | |
for _, n := range nums { | |
out <- n | |
} | |
close(out) | |
}() | |
return out | |
} | |
func square(done <-chan struct{}, in <-chan int) <-chan int { | |
out := make(chan int) | |
go func() { | |
for n := range in { | |
select { | |
case out <- n * n: | |
case <-done: | |
return | |
} | |
} | |
close(out) | |
}() | |
return out | |
} | |
func main() { | |
done := make(chan struct{}) | |
defer close(done) | |
in := gen(2, 3, 4) | |
c1 := square(done, in) | |
c2 := square(done, in) | |
out := merge(done, c1, c2) | |
fmt.Println(<-out) | |
} | |
func merge(done <-chan struct{}, cs ...<-chan int) <-chan int { | |
var wg sync.WaitGroup | |
out := make(chan int) | |
output := func(c <-chan int) { | |
defer wg.Done() | |
for n := range c { | |
select { | |
case out <- n: | |
case <-done: | |
return | |
} | |
} | |
} | |
wg.Add(len(cs)) | |
for _, c := range cs { | |
go output(c) | |
} | |
go func() { | |
wg.Wait() | |
close(out) | |
}() | |
return out | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment