Skip to content

Instantly share code, notes, and snippets.

@fuyufjh
Last active November 30, 2016 02:22
Show Gist options
  • Save fuyufjh/b612c4ea000c943cc9adfc98533a37c8 to your computer and use it in GitHub Desktop.
Save fuyufjh/b612c4ea000c943cc9adfc98533a37c8 to your computer and use it in GitHub Desktop.
Golang Cheatsheet
// 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)
}
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
}
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