├── README.md └── Golang-cheat-sheet.md /README.md: -------------------------------------------------------------------------------- 1 | # Go 备忘单 2 | 3 | # 索引 4 | 5 | 6 | 1. [基础语法](#基础语法) 7 | 2. [运算符](#运算符) 8 | - [算术运算符](#算术运算符) 9 | - [比较运算符](#比较运算符) 10 | - [逻辑运算符](#逻辑运算符) 11 | - [其他](#其他) 12 | 3. [声明](#声明) 13 | 4. [函数](#函数) 14 | - [作为值和闭包的函数](#作为值和闭包的函数) 15 | - [可变参数函数](#可变参数函数) 16 | 5. [内置类型](#内置类型) 17 | 6. [类型转换](#类型转换) 18 | 7. [包](#包) 19 | 8. [控制结构](#控制结构) 20 | - [If条件](#条件) 21 | - [循环](#循环) 22 | - [Switch](#switch) 23 | 9. [数组、切片、范围 ](#数组、切片、范围 ) 24 | - [数组](#数组) 25 | - [切片](#切片) 26 | - [操作数组和切片](#操作数组和切片) 27 | 10. [映射](#映射) 28 | 11. [结构体](#结构体) 29 | 12. [指针](#指针) 30 | 13. [接口](#接口) 31 | 14. [嵌入组合](#嵌入组合) 32 | 15. [错误](#错误) 33 | 16. [并发](#并发) 34 | - [协程](#协程) 35 | - [通道](#通道) 36 | - [通道原理](#channel的原理) 37 | 17. [打印输出](#打印) 38 | 18. [代码片段](#代码片段) 39 | - [HTTP服务器](#HTTP服务器) 40 | 41 | 42 | 43 | ## 引言 44 | 45 | 大部分的例子引用于 [A Tour of Go](http://tour.golang.org/),非常棒的Go语言介绍。 46 | 47 | 如果你是Go的新手,请认真阅读Tour。 48 | 49 | ## Go核心技术 50 | 51 | - 强类型语言 52 | - 静态类型 53 | - 语法类似于C (更少的括号和分号) 和 Oberon-2的struct结构体 54 | - 编译为本地代码(没有java虚拟机) 55 | - 没有类,但有带方法的结构 56 | - 接口 57 | - 没有实现继承,只有内嵌组合就够了 58 | - 函数是一等公民 59 | - 函数可以返回多值 60 | - 有闭包 61 | - 有指针,但没有指针的运算 62 | - 内置的并发原语:协程和通道 63 | 64 | # 基础语法 65 | 66 | ## 你好,世界 67 | 68 | 文件 `hello.go`: 69 | 70 | ```go 71 | package main 72 | 73 | import "fmt" 74 | 75 | func main() { 76 | fmt.Println("Hello Go") 77 | } 78 | ``` 79 | 80 | `$ go run hello.go` 81 | 82 | ## 运算符 83 | 84 | ### 算术运算符 85 | 86 | | 运算符号 | 描述 | 87 | | -------- | ------ | 88 | | `+` | 加 | 89 | | `-` | 减 | 90 | | `*` | 乘 | 91 | | `/` | 商 | 92 | | `%` | 取余 | 93 | | `&` | 与 | 94 | | `\|` | 或 | 95 | | `^` | 位异或 | 96 | | `&^` | 位与非 | 97 | | `<<` | 左移 | 98 | | `>>` | 右移 | 99 | 100 | ### 比较运算符 101 | 102 | | 运算符 | 描述 | 103 | | ------ | --------------------- | 104 | | `==` | 等于 | 105 | | `!=` | 不等于 | 106 | | `<` | 小于 | 107 | | `<=` | 小于等于 | 108 | | `>` | 大于 | 109 | | `>=` | 大于等于 | 110 | 111 | ### 逻辑运算符 112 | 113 | | 运算符 | 描述 | 114 | | ------ | ------ | 115 | | `&&` | 逻辑与 | 116 | | `\|\|` | 逻辑或 | 117 | | `!` | 逻辑非 | 118 | 119 | ### 其他 120 | 121 | | 运算符 | 描述 | 122 | | ------ | -------------------------------------------- | 123 | | `&` | 对象地址 / 创建指针对象 | 124 | | `*` | 指针解引用 | 125 | | `<-` | 发送 / 接收 运算符 (可查看文章下面的Channel) | 126 | 127 | ## 声明 128 | 129 | 具体类型需要写在识别符之后! 130 | 131 | ```go 132 | var foo int // 声明未初始化 133 | var foo int = 42 // 声明并初始化 134 | var foo, bar int = 42, 1302 // 一次声明并初始化多个遍历 135 | var foo = 42 // 省略类型, 自动推断类型 136 | foo := 42 // 速写方式,只在函数内部,省略var书写,类型常是隐式的 137 | const constant = "This is a constant" 138 | ``` 139 | 140 | ## 函数 141 | 142 | ```go 143 | // 一个简单的函数 144 | func functionName() {} 145 | 146 | // 带参数的函数 (再次提示, 类型放在标识符后面) 147 | func functionName(param1 string, param2 int) {} 148 | 149 | // 带同一类型参数的函数 150 | func functionName(param1, param2 int) {} 151 | 152 | // 返回类型声明 153 | func functionName() int { 154 | return 42 155 | } 156 | 157 | // 一次能返回多个值 158 | func returnMulti() (int, string) { 159 | return 42, "foobar" 160 | } 161 | var x, str = returnMulti() 162 | 163 | // 返回多个已命名过的值可以直接简化成return 164 | func returnMulti2() (n int, s string) { 165 | n = 42 166 | s = "foobar" 167 | // n和s会被return 168 | return 169 | } 170 | var x, str = returnMulti2() 171 | 172 | ``` 173 | 174 | ### 作为值和闭包的函数 175 | 176 | ```go 177 | func main() { 178 | // 赋值函数给一个变量 179 | add := func(a, b int) int { 180 | return a + b 181 | } 182 | // 用变量名字调用函数 183 | fmt.Println(add(3, 4)) 184 | } 185 | 186 | // 闭包,词法作用域:其他函数可以访问在scope函数里定义的值 187 | func scope() func() int{ 188 | outer_var := 2 189 | foo := func() int { return outer_var} 190 | return foo 191 | } 192 | 193 | func another_scope() func() int{ 194 | // 不会编译,因为outer_var和foo没有在这个作用域内声明 195 | outer_var = 444 196 | return foo 197 | } 198 | 199 | 200 | // 闭包:不会改变函数外的变量,而是重新声明它们! 201 | func outer() (func() int, int) { 202 | outer_var := 2 203 | inner := func() int { 204 | outer_var += 99 // 试图在作用域中改变outer_var 205 | return outer_var // => 101 (outter_var是重新声明的变量 206 | // 变量只能在函数内部可使用) 207 | } 208 | return inner, outer_var // => 101, 2 (outer_var 一直是2, 没有被闭包内部改变!) 209 | } 210 | ``` 211 | 212 | ### 可变参数函数 213 | 214 | ```go 215 | func main() { 216 | fmt.Println(adder(1, 2, 3)) // 6 217 | fmt.Println(adder(9, 9)) // 18 218 | 219 | nums := []int{10, 20, 30} 220 | fmt.Println(adder(nums...)) // 60 221 | } 222 | 223 | // 使用 ... 可以在最后一个参数的类型名之前替代0个或更多的参数。 224 | // 这个函数跟其他函数一样可以被调用并且可以传递更多的参数 225 | func adder(args ...int) int { 226 | total := 0 227 | for _, v := range args { // Iterates over the arguments whatever the number. 228 | total += v 229 | } 230 | return total 231 | } 232 | ``` 233 | 234 | ## 内置类型 235 | 236 | ```go 237 | bool 238 | 239 | string 240 | 241 | int int8 int16 int32 int64 242 | uint uint8 uint16 uint32 uint64 uintptr 243 | 244 | byte // uint8的别名 245 | 246 | rune // int32的别名 ~= 一个字符(Unicode编码点)-非常(霸道)Viking 247 | 248 | float32 float64 249 | 250 | complex64 complex128 251 | ``` 252 | 253 | ## 类型转换 254 | 255 | ```go 256 | var i int = 42 257 | var f float64 = float64(i) 258 | var u uint = uint(f) 259 | 260 | // 可选的语法规则 261 | i := 42 262 | f := float64(i) 263 | u := uint(f) 264 | ``` 265 | 266 | ## 包 267 | 268 | - 包声明在每个源文件的头部 269 | - 可执行文件在 `main`包里 270 | - 约定: 包名 == import路径的最后一个词名 271 | - 大写字母标识符: 公开的 (外部包可引用的) 272 | - 小写字母标识符: 私有的(外部包不可引用的) 273 | 274 | ## 控制结构 275 | 276 | ### 条件 277 | 278 | ```go 279 | func main() { 280 | // 基础的 281 | if x > 0 { 282 | return x 283 | } else { 284 | return -x 285 | } 286 | 287 | // 可以在条件之前放一个表达式语句 288 | if a := b + c; a < 42 { 289 | return a 290 | } else { 291 | return a - 42 292 | } 293 | 294 | // if内部的类型断言 295 | var val interface{} 296 | val = "foo" 297 | if str, ok := val.(string); ok { 298 | fmt.Println(str) 299 | } 300 | } 301 | ``` 302 | 303 | ### 循环 304 | 305 | ```go 306 | // 这里只有for,没有while,until 307 | for i := 1; i < 10; i++ { 308 | } 309 | for ; i < 10; { // while - 循环 310 | } 311 | for i < 10 { // 如果只有一个条件的话可以省略分号; 312 | } 313 | for { // 可以省略条件 ~ while (true) 314 | } 315 | ``` 316 | 317 | ### Switch 318 | 319 | ```go 320 | // switch 语句 321 | switch operatingSystem { 322 | case "darwin": 323 | fmt.Println("Mac OS Hipster") 324 | // cases会自动break, 而不是通过defaultbreak 325 | case "linux": 326 | fmt.Println("Linux Geek") 327 | default: 328 | // Windows, BSD, ... 329 | fmt.Println("Other") 330 | } 331 | 332 | // 与for和if一样,可以在switch值之前加一个赋值语句 333 | switch os := runtime.GOOS; os { 334 | case "darwin": ... 335 | } 336 | 337 | // 可以在 switch cases中做比较 338 | number := 42 339 | switch { 340 | case number < 42: 341 | fmt.Println("Smaller") 342 | case number == 42: 343 | fmt.Println("Equal") 344 | case number > 42: 345 | fmt.Println("Greater") 346 | } 347 | 348 | // 在case列表中可以用多个用逗号分隔 349 | var char byte = '?' 350 | switch char { 351 | case ' ', '?', '&', '=', '#', '+', '%': 352 | fmt.Println("Should escape") 353 | } 354 | ``` 355 | 356 | ## 数组、切片、范围 357 | 358 | ### 数组 359 | 360 | ```go 361 | var a [10]int // 声明了一个长度为10 的int数组,数组长度是类型的一部分 362 | a[3] = 42 // 设置元素的值 363 | i := a[3] // 读取元素 364 | 365 | // 声明并初始化 366 | var a = [2]int{1, 2} 367 | a := [2]int{1, 2} //简写法 368 | a := [...]int{1, 2} // ...省略号 -> 编译器计算出数组长度 369 | ``` 370 | 371 | ### 切片 372 | 373 | ```go 374 | var a []int // 声明一个切片,-类似与一个数组,但是长度为指明 375 | var a = []int {1, 2, 3, 4} // 声明并初始化一个切片(背后是底层隐式的数组) 376 | a := []int{1, 2, 3, 4} // 简写法 377 | chars := []string{0:"a", 2:"c", 1: "b"} // ["a", "b", "c"] 378 | 379 | var b = a[lo:hi] // 创建一个切片(可看成数组)索引从lo到hi 380 | var b = a[1:4] // 索引从1到3的切片 381 | var b = a[:3] // 省略前面的索引意指0 382 | var b = a[3:] // 省略后面的索引意指len(a) 383 | a = append(a,17,3) // 在切片a后面追加item 384 | c := append(a,b...) // 连接切片a和b 385 | 386 | // 用make创建切片 387 | a = make([]byte, 5, 5) // 第一个参数代表长度,第二个代表容量 388 | a = make([]byte, 5) // 容量是可选参数 389 | 390 | // 从数组里面创建切片 391 | x := [3]string{"Лайка", "Белка", "Стрелка"} 392 | s := x[:] // 一个切片引用了x的存储容量 393 | ``` 394 | 395 | ### 操作数组和切片 396 | 397 | `len(a)`可以算出一个数组或切片的长度,它是内建函数,而不是一个数组的属性/方法 398 | 399 | ```go 400 | // 对一个数组/一个切片的循环 401 | for i, e := range a { 402 | // i 是索引, e 是元素 403 | } 404 | 405 | // 如果只要e: 406 | for _, e := range a { 407 | // e 是元素 408 | } 409 | 410 | // 如果只需要索引 411 | for i := range a { 412 | } 413 | 414 | // 在Go1.4之前,如果你不使用i和e,会得到一个编译错误。 415 | // Go1.4引入了一种无变量形式,就可以这样使用 416 | for range time.Tick(time.Second) { 417 | // do it once a sec 418 | } 419 | 420 | ``` 421 | 422 | ## 映射 423 | 424 | ```go 425 | var m map[string]int 426 | m = make(map[string]int) 427 | m["key"] = 42 428 | fmt.Println(m["key"]) 429 | 430 | delete(m, "key") 431 | 432 | elem, ok := m["key"] // 再次测试key是否存在 433 | 434 | // 字符组合的map 435 | var m = map[string]Vertex{ 436 | "Bell Labs": {40.68433, -74.39967}, 437 | "Google": {37.42202, -122.08408}, 438 | } 439 | 440 | ``` 441 | 442 | ## 结构体 443 | 444 | 这里没有类,只有结构体,结构体可以有方法 445 | 446 | ```go 447 | // 结构体是一种类型. 代表字段的集合 448 | 449 | // 声明 450 | type Vertex struct { 451 | X, Y int 452 | } 453 | 454 | // 创建 455 | var v = Vertex{1, 2} 456 | var v = Vertex{X: 1, Y: 2} // 通过key-value创建一个结构体实体 457 | var v = []Vertex{{1,2},{5,2},{5,5}} // 初始化结构体 切片 458 | 459 | // 访问字段 460 | v.X = 4 461 | 462 | // 您可以在struct中声明方法。想要声明的结构体方法(接收类型)在func关键字和 463 | // 方法名之间。结构体会复制在每个方法()调用之前 464 | func (v Vertex) Abs() float64 { 465 | return math.Sqrt(v.X*v.X + v.Y*v.Y) 466 | } 467 | 468 | // 调用方法 469 | v.Abs() 470 | 471 | // 对于改变变量的方法,需要通过使用结构体指针作为类型。这样在调用过程中结构体的值将不会被拷贝【所谓的值拷贝】 472 | func (v *Vertex) add(n float64) { 473 | v.X += n 474 | v.Y += n 475 | } 476 | 477 | ``` 478 | 479 | **匿名结构体:** 480 | 比起用 `map[string]interface{}`成本更低更安全 481 | 482 | ```go 483 | point := struct { 484 | X, Y int 485 | }{1, 2} 486 | ``` 487 | 488 | ## 指针 489 | 490 | ```go 491 | p := Vertex{1, 2} // p 是一个 Vertex 492 | q := &p // q 是指向 Vertex的一个指针 493 | r := &Vertex{1, 2} // r 也是指向 Vertex的一个指针 494 | 495 | // Vertex 的指针类型是 *Vertex 496 | 497 | var s *Vertex = new(Vertex) // new 创建了一个指针指向了新的结构体实体 498 | ``` 499 | 500 | ## 接口 501 | 502 | ```go 503 | // 接口声明 504 | type Awesomizer interface { 505 | Awesomize() string 506 | } 507 | 508 | // 类型没有声明实现的接口 509 | type Foo struct {} 510 | 511 | // 相反,如果它们实现了所有必需的方法,类型就会隐式地满足接口 512 | func (foo Foo) Awesomize() string { 513 | return "Awesome!" 514 | } 515 | ``` 516 | 517 | ## 嵌入组合 518 | 519 | 在Go中没有子类,而是interface和struct的内嵌组合。 520 | 521 | ```go 522 | // ReadWriter 的实现必须满足Reader和Writer 523 | type ReadWriter interface { 524 | Reader 525 | Writer 526 | } 527 | 528 | // Server 公开了Logger所有的方法 529 | type Server struct { 530 | Host string 531 | Port int 532 | *log.Logger 533 | } 534 | 535 | // 按照通常的方式初始化组合类型 536 | server := &Server{"localhost", 80, log.New(...)} 537 | 538 | // 可以使用在嵌入式结构中实现的方法 539 | server.Log(...) // 调用 server.Logger.Log(...) 540 | 541 | // 嵌入式结构的字段名是它的类型名称(在Logger中) 542 | var logger *log.Logger = server.Logger 543 | ``` 544 | 545 | ## 错误 546 | 547 | 没有异常处理 . 可能产生错误的函数只是声明了 `Error`类型的返回值. 下面是 `Error` 的interface: 548 | 549 | ```go 550 | type error interface { 551 | Error() string 552 | } 553 | ``` 554 | 555 | 下面方法可能会返回一个err: 556 | 557 | ```go 558 | func doStuff() (int, error) { 559 | } 560 | 561 | func main() { 562 | result, err := doStuff() 563 | if err != nil { 564 | // 处理错误 565 | } else { 566 | // 无错误,使用正确结果 567 | } 568 | } 569 | ``` 570 | 571 | # 并发 572 | 573 | ## 协程 574 | 575 | Goroutines 是轻量级的线程 (被Go操纵管理,而不是操作系统线程). `go f(a, b)` 开启了一个新的运行f函数的goroutine (`f`是个函数). 576 | 577 | ```go 578 | // 只是一个函数(会被作为一个goroutine开始执行) 579 | func doStuff(s string) { 580 | } 581 | 582 | func main() { 583 | // 用一个已命名的函数开启goroutine 584 | go doStuff("foobar") 585 | 586 | // 用一个匿名开启goroutine 587 | go func (x int) { 588 | // 方法体放在这里 589 | }(42) 590 | } 591 | ``` 592 | 593 | ## 通道 594 | 595 | ```go 596 | ch := make(chan int) // 创建一个int类型的channel 597 | ch <- 42 // 给channel ch发送一个值 598 | v := <-ch // 从ch接受一个值 599 | 600 | // 无缓冲的channle会阻塞. 没有值可读的时候会阻塞,写也是,直到有值可读。 601 | 602 | // 创建一个带缓冲的channel,如果写的未读值小于buffer大小,那么写入缓冲通道就不会阻塞。 603 | ch := make(chan int, 100) 604 | 605 | close(ch) // 关闭通道(只有发送方能关闭) 606 | 607 | // 如果channel已经关闭,可以从通道中读取和测试 608 | v, ok := <-ch 609 | 610 | // 如果ok是false,说明channel已经关闭 611 | 612 | // 一直从channel里读直到关闭 613 | for i := range ch { 614 | fmt.Println(i) 615 | } 616 | 617 | // 在多个通道操作上select ,如果一个没有阻塞,与之对应的case将被执行 618 | func doStuff(channelOut, channelIn chan int) { 619 | select { 620 | case channelOut <- 42: 621 | fmt.Println("We could write to channelOut!") 622 | case x := <- channelIn: 623 | fmt.Println("We could read from channelIn") 624 | case <-time.After(time.Second * 1): 625 | fmt.Println("timeout") 626 | } 627 | } 628 | ``` 629 | 630 | ### Channel的原理 631 | 632 | - 给一个nil的channel发送永远会阻塞 633 | 634 | ```go 635 | var c chan string 636 | c <- "Hello, World!" 637 | // fatal error: all goroutines are asleep - deadlock! 638 | ``` 639 | 640 | - 从一个nil的channel接受也会永远阻塞 641 | 642 | ```go 643 | var c chan string 644 | fmt.Println(<-c) 645 | // fatal error: all goroutines are asleep - deadlock! 646 | ``` 647 | 648 | - 给一个已关闭的channel发送会panic 649 | 650 | ```go 651 | var c = make(chan string, 1) 652 | c <- "Hello, World!" 653 | close(c) 654 | c <- "Hello, Panic!" 655 | // panic: send on closed channel 656 | ``` 657 | 658 | - 从一个关闭的channel接受会立刻返回一个0值 659 | 660 | ```go 661 | var c = make(chan int, 2) 662 | c <- 1 663 | c <- 2 664 | close(c) 665 | for i := 0; i < 3; i++ { 666 | fmt.Printf("%d ", <-c) 667 | } 668 | // 1 2 0 669 | ``` 670 | 671 | ## 打印 672 | 673 | ```go 674 | fmt.Println("Hello, 你好, नमस्ते, Привет, ᎣᏏᏲ") // 基本的 print, 会自动换行 675 | p := struct { X, Y int }{ 17, 2 } 676 | fmt.Println( "My point:", p, "x coord=", p.X ) // print 结构体,整型等等 677 | s := fmt.Sprintln( "My point:", p, "x coord=", p.X ) // print 字符串变量 678 | 679 | fmt.Printf("%d hex:%x bin:%b fp:%f sci:%e",17,17,17,17.0,17.0) // c-ish 格式化 680 | s2 := fmt.Sprintf( "%d %f", 17, 17.0 ) // 格式化输出字符串变量 681 | 682 | hellomsg := ` 683 | "Hello" in Chinese is 你好 ('Ni Hao') 684 | "Hello" in Hindi is नमस्ते ('Namaste') 685 | ` // 多行的字符串, 用`` 686 | ``` 687 | 688 | # 代码片段 689 | 690 | ## HTTP服务器 691 | 692 | ```go 693 | package main 694 | 695 | import ( 696 | "fmt" 697 | "net/http" 698 | ) 699 | 700 | // 定义了一个响应体struct 701 | type Hello struct{} 702 | 703 | // 让Hello去实现ServeHTTP 方法 (在 interface http.Handler里面已经定义) 704 | func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) { 705 | fmt.Fprint(w, "Hello!") 706 | } 707 | 708 | func main() { 709 | var h Hello 710 | http.ListenAndServe("localhost:4000", h) 711 | } 712 | 713 | // 这里是 http.ServeHTTP的方法署名: 714 | // type Handler interface { 715 | // ServeHTTP(w http.ResponseWriter, r *http.Request) 716 | // } 717 | ``` -------------------------------------------------------------------------------- /Golang-cheat-sheet.md: -------------------------------------------------------------------------------- 1 | # Go Cheat Sheet 2 | 3 | # Index 4 | 1. [Basic Syntax](#basic-syntax) 5 | 2. [Operators](#operators) 6 | * [Arithmetic](#arithmetic) 7 | * [Comparison](#comparison) 8 | * [Logical](#logical) 9 | * [Other](#other) 10 | 3. [Declarations](#declarations) 11 | 4. [Functions](#functions) 12 | * [Functions as values and closures](#functions-as-values-and-closures) 13 | * [Variadic Functions](#variadic-functions) 14 | 5. [Built-in Types](#built-in-types) 15 | 6. [Type Conversions](#type-conversions) 16 | 7. [Packages](#packages) 17 | 8. [Control structures](#control-structures) 18 | * [If](#if) 19 | * [Loops](#loops) 20 | * [Switch](#switch) 21 | 9. [Arrays, Slices, Ranges](#arrays-slices-ranges) 22 | * [Arrays](#arrays) 23 | * [Slices](#slices) 24 | * [Operations on Arrays and Slices](#operations-on-arrays-and-slices) 25 | 10. [Maps](#maps) 26 | 11. [Structs](#structs) 27 | 12. [Pointers](#pointers) 28 | 13. [Interfaces](#interfaces) 29 | 14. [Embedding](#embedding) 30 | 15. [Errors](#errors) 31 | 16. [Concurrency](#concurrency) 32 | * [Goroutines](#goroutines) 33 | * [Channels](#channels) 34 | * [Channel Axioms](#channel-axioms) 35 | 17. [Printing](#printing) 36 | 18. [Snippets](#snippets) 37 | * [Http-Server](#http-server) 38 | 39 | ## Credits 40 | 41 | Most example code taken from [A Tour of Go](http://tour.golang.org/), which is an excellent introduction to Go. 42 | If you're new to Go, do that tour. Seriously. 43 | 44 | ## Go in a Nutshell 45 | 46 | * Imperative language 47 | * Statically typed 48 | * Syntax tokens similar to C (but less parentheses and no semicolons) and the structure to Oberon-2 49 | * Compiles to native code (no JVM) 50 | * No classes, but structs with methods 51 | * Interfaces 52 | * No implementation inheritance. There's [type embedding](http://golang.org/doc/effective%5Fgo.html#embedding), though. 53 | * Functions are first class citizens 54 | * Functions can return multiple values 55 | * Has closures 56 | * Pointers, but not pointer arithmetic 57 | * Built-in concurrency primitives: Goroutines and Channels 58 | 59 | # Basic Syntax 60 | 61 | ## Hello World 62 | File `hello.go`: 63 | ```go 64 | package main 65 | 66 | import "fmt" 67 | 68 | func main() { 69 | fmt.Println("Hello Go") 70 | } 71 | ``` 72 | `$ go run hello.go` 73 | 74 | ## Operators 75 | ### Arithmetic 76 | |Operator|Description| 77 | |--------|-----------| 78 | |`+`|addition| 79 | |`-`|subtraction| 80 | |`*`|multiplication| 81 | |`/`|quotient| 82 | |`%`|remainder| 83 | |`&`|bitwise and| 84 | |`\|`|bitwise or| 85 | |`^`|bitwise xor| 86 | |`&^`|bit clear (and not)| 87 | |`<<`|left shift| 88 | |`>>`|right shift| 89 | 90 | ### Comparison 91 | |Operator|Description| 92 | |--------|-----------| 93 | |`==`|equal| 94 | |`!=`|not equal| 95 | |`<`|less than| 96 | |`<=`|less than or equal| 97 | |`>`|greater than| 98 | |`>=`|greater than or equal| 99 | 100 | ### Logical 101 | |Operator|Description| 102 | |--------|-----------| 103 | |`&&`|logical and| 104 | |`\|\|`|logical or| 105 | |`!`|logical not| 106 | 107 | ### Other 108 | |Operator|Description| 109 | |--------|-----------| 110 | |`&`|address of / create pointer| 111 | |`*`|dereference pointer| 112 | |`<-`|send / receive operator (see 'Channels' below)| 113 | 114 | ## Declarations 115 | Type goes after identifier! 116 | ```go 117 | var foo int // declaration without initialization 118 | var foo int = 42 // declaration with initialization 119 | var foo, bar int = 42, 1302 // declare and init multiple vars at once 120 | var foo = 42 // type omitted, will be inferred 121 | foo := 42 // shorthand, only in func bodies, omit var keyword, type is always implicit 122 | const constant = "This is a constant" 123 | ``` 124 | 125 | ## Functions 126 | ```go 127 | // a simple function 128 | func functionName() {} 129 | 130 | // function with parameters (again, types go after identifiers) 131 | func functionName(param1 string, param2 int) {} 132 | 133 | // multiple parameters of the same type 134 | func functionName(param1, param2 int) {} 135 | 136 | // return type declaration 137 | func functionName() int { 138 | return 42 139 | } 140 | 141 | // Can return multiple values at once 142 | func returnMulti() (int, string) { 143 | return 42, "foobar" 144 | } 145 | var x, str = returnMulti() 146 | 147 | // Return multiple named results simply by return 148 | func returnMulti2() (n int, s string) { 149 | n = 42 150 | s = "foobar" 151 | // n and s will be returned 152 | return 153 | } 154 | var x, str = returnMulti2() 155 | 156 | ``` 157 | 158 | ### Functions As Values And Closures 159 | ```go 160 | func main() { 161 | // assign a function to a name 162 | add := func(a, b int) int { 163 | return a + b 164 | } 165 | // use the name to call the function 166 | fmt.Println(add(3, 4)) 167 | } 168 | 169 | // Closures, lexically scoped: Functions can access values that were 170 | // in scope when defining the function 171 | func scope() func() int{ 172 | outer_var := 2 173 | foo := func() int { return outer_var} 174 | return foo 175 | } 176 | 177 | func another_scope() func() int{ 178 | // won't compile because outer_var and foo not defined in this scope 179 | outer_var = 444 180 | return foo 181 | } 182 | 183 | 184 | // Closures: don't mutate outer vars, instead redefine them! 185 | func outer() (func() int, int) { 186 | outer_var := 2 187 | inner := func() int { 188 | outer_var += 99 // attempt to mutate outer_var from outer scope 189 | return outer_var // => 101 (but outer_var is a newly redefined 190 | // variable visible only inside inner) 191 | } 192 | return inner, outer_var // => 101, 2 (outer_var is still 2, not mutated by inner!) 193 | } 194 | ``` 195 | 196 | ### Variadic Functions 197 | ```go 198 | func main() { 199 | fmt.Println(adder(1, 2, 3)) // 6 200 | fmt.Println(adder(9, 9)) // 18 201 | 202 | nums := []int{10, 20, 30} 203 | fmt.Println(adder(nums...)) // 60 204 | } 205 | 206 | // By using ... before the type name of the last parameter you can indicate that it takes zero or more of those parameters. 207 | // The function is invoked like any other function except we can pass as many arguments as we want. 208 | func adder(args ...int) int { 209 | total := 0 210 | for _, v := range args { // Iterates over the arguments whatever the number. 211 | total += v 212 | } 213 | return total 214 | } 215 | ``` 216 | 217 | ## Built-in Types 218 | ``` 219 | bool 220 | 221 | string 222 | 223 | int int8 int16 int32 int64 224 | uint uint8 uint16 uint32 uint64 uintptr 225 | 226 | byte // alias for uint8 227 | 228 | rune // alias for int32 ~= a character (Unicode code point) - very Viking 229 | 230 | float32 float64 231 | 232 | complex64 complex128 233 | ``` 234 | 235 | ## Type Conversions 236 | ```go 237 | var i int = 42 238 | var f float64 = float64(i) 239 | var u uint = uint(f) 240 | 241 | // alternative syntax 242 | i := 42 243 | f := float64(i) 244 | u := uint(f) 245 | ``` 246 | 247 | ## Packages 248 | * Package declaration at top of every source file 249 | * Executables are in package `main` 250 | * Convention: package name == last name of import path (import path `math/rand` => package `rand`) 251 | * Upper case identifier: exported (visible from other packages) 252 | * Lower case identifier: private (not visible from other packages) 253 | 254 | ## Control structures 255 | 256 | ### If 257 | ```go 258 | func main() { 259 | // Basic one 260 | if x > 0 { 261 | return x 262 | } else { 263 | return -x 264 | } 265 | 266 | // You can put one statement before the condition 267 | if a := b + c; a < 42 { 268 | return a 269 | } else { 270 | return a - 42 271 | } 272 | 273 | // Type assertion inside if 274 | var val interface{} 275 | val = "foo" 276 | if str, ok := val.(string); ok { 277 | fmt.Println(str) 278 | } 279 | } 280 | ``` 281 | 282 | ### Loops 283 | ```go 284 | // There's only `for`, no `while`, no `until` 285 | for i := 1; i < 10; i++ { 286 | } 287 | for ; i < 10; { // while - loop 288 | } 289 | for i < 10 { // you can omit semicolons if there is only a condition 290 | } 291 | for { // you can omit the condition ~ while (true) 292 | } 293 | ``` 294 | 295 | ### Switch 296 | ```go 297 | // switch statement 298 | switch operatingSystem { 299 | case "darwin": 300 | fmt.Println("Mac OS Hipster") 301 | // cases break automatically, no fallthrough by default 302 | case "linux": 303 | fmt.Println("Linux Geek") 304 | default: 305 | // Windows, BSD, ... 306 | fmt.Println("Other") 307 | } 308 | 309 | // as with for and if, you can have an assignment statement before the switch value 310 | switch os := runtime.GOOS; os { 311 | case "darwin": ... 312 | } 313 | 314 | // you can also make comparisons in switch cases 315 | number := 42 316 | switch { 317 | case number < 42: 318 | fmt.Println("Smaller") 319 | case number == 42: 320 | fmt.Println("Equal") 321 | case number > 42: 322 | fmt.Println("Greater") 323 | } 324 | 325 | // cases can be presented in comma-separated lists 326 | var char byte = '?' 327 | switch char { 328 | case ' ', '?', '&', '=', '#', '+', '%': 329 | fmt.Println("Should escape") 330 | } 331 | ``` 332 | 333 | ## Arrays, Slices, Ranges 334 | 335 | ### Arrays 336 | ```go 337 | var a [10]int // declare an int array with length 10. Array length is part of the type! 338 | a[3] = 42 // set elements 339 | i := a[3] // read elements 340 | 341 | // declare and initialize 342 | var a = [2]int{1, 2} 343 | a := [2]int{1, 2} //shorthand 344 | a := [...]int{1, 2} // elipsis -> Compiler figures out array length 345 | ``` 346 | 347 | ### Slices 348 | ```go 349 | var a []int // declare a slice - similar to an array, but length is unspecified 350 | var a = []int {1, 2, 3, 4} // declare and initialize a slice (backed by the array given implicitly) 351 | a := []int{1, 2, 3, 4} // shorthand 352 | chars := []string{0:"a", 2:"c", 1: "b"} // ["a", "b", "c"] 353 | 354 | var b = a[lo:hi] // creates a slice (view of the array) from index lo to hi-1 355 | var b = a[1:4] // slice from index 1 to 3 356 | var b = a[:3] // missing low index implies 0 357 | var b = a[3:] // missing high index implies len(a) 358 | a = append(a,17,3) // append items to slice a 359 | c := append(a,b...) // concatenate slices a and b 360 | 361 | // create a slice with make 362 | a = make([]byte, 5, 5) // first arg length, second capacity 363 | a = make([]byte, 5) // capacity is optional 364 | 365 | // create a slice from an array 366 | x := [3]string{"Лайка", "Белка", "Стрелка"} 367 | s := x[:] // a slice referencing the storage of x 368 | ``` 369 | 370 | ### Operations on Arrays and Slices 371 | `len(a)` gives you the length of an array/a slice. It's a built-in function, not a attribute/method on the array. 372 | 373 | ```go 374 | // loop over an array/a slice 375 | for i, e := range a { 376 | // i is the index, e the element 377 | } 378 | 379 | // if you only need e: 380 | for _, e := range a { 381 | // e is the element 382 | } 383 | 384 | // ...and if you only need the index 385 | for i := range a { 386 | } 387 | 388 | // In Go pre-1.4, you'll get a compiler error if you're not using i and e. 389 | // Go 1.4 introduced a variable-free form, so that you can do this 390 | for range time.Tick(time.Second) { 391 | // do it once a sec 392 | } 393 | 394 | ``` 395 | 396 | ## Maps 397 | 398 | ```go 399 | var m map[string]int 400 | m = make(map[string]int) 401 | m["key"] = 42 402 | fmt.Println(m["key"]) 403 | 404 | delete(m, "key") 405 | 406 | elem, ok := m["key"] // test if key "key" is present and retrieve it, if so 407 | 408 | // map literal 409 | var m = map[string]Vertex{ 410 | "Bell Labs": {40.68433, -74.39967}, 411 | "Google": {37.42202, -122.08408}, 412 | } 413 | 414 | ``` 415 | 416 | ## Structs 417 | 418 | There are no classes, only structs. Structs can have methods. 419 | ```go 420 | // A struct is a type. It's also a collection of fields 421 | 422 | // Declaration 423 | type Vertex struct { 424 | X, Y int 425 | } 426 | 427 | // Creating 428 | var v = Vertex{1, 2} 429 | var v = Vertex{X: 1, Y: 2} // Creates a struct by defining values with keys 430 | var v = []Vertex{{1,2},{5,2},{5,5}} // Initialize a slice of structs 431 | 432 | // Accessing members 433 | v.X = 4 434 | 435 | // You can declare methods on structs. The struct you want to declare the 436 | // method on (the receiving type) comes between the the func keyword and 437 | // the method name. The struct is copied on each method call(!) 438 | func (v Vertex) Abs() float64 { 439 | return math.Sqrt(v.X*v.X + v.Y*v.Y) 440 | } 441 | 442 | // Call method 443 | v.Abs() 444 | 445 | // For mutating methods, you need to use a pointer (see below) to the Struct 446 | // as the type. With this, the struct value is not copied for the method call. 447 | func (v *Vertex) add(n float64) { 448 | v.X += n 449 | v.Y += n 450 | } 451 | 452 | ``` 453 | **Anonymous structs:** 454 | Cheaper and safer than using `map[string]interface{}`. 455 | ```go 456 | point := struct { 457 | X, Y int 458 | }{1, 2} 459 | ``` 460 | 461 | ## Pointers 462 | ```go 463 | p := Vertex{1, 2} // p is a Vertex 464 | q := &p // q is a pointer to a Vertex 465 | r := &Vertex{1, 2} // r is also a pointer to a Vertex 466 | 467 | // The type of a pointer to a Vertex is *Vertex 468 | 469 | var s *Vertex = new(Vertex) // new creates a pointer to a new struct instance 470 | ``` 471 | 472 | ## Interfaces 473 | ```go 474 | // interface declaration 475 | type Awesomizer interface { 476 | Awesomize() string 477 | } 478 | 479 | // types do *not* declare to implement interfaces 480 | type Foo struct {} 481 | 482 | // instead, types implicitly satisfy an interface if they implement all required methods 483 | func (foo Foo) Awesomize() string { 484 | return "Awesome!" 485 | } 486 | ``` 487 | 488 | ## Embedding 489 | 490 | There is no subclassing in Go. Instead, there is interface and struct embedding. 491 | 492 | ```go 493 | // ReadWriter implementations must satisfy both Reader and Writer 494 | type ReadWriter interface { 495 | Reader 496 | Writer 497 | } 498 | 499 | // Server exposes all the methods that Logger has 500 | type Server struct { 501 | Host string 502 | Port int 503 | *log.Logger 504 | } 505 | 506 | // initialize the embedded type the usual way 507 | server := &Server{"localhost", 80, log.New(...)} 508 | 509 | // methods implemented on the embedded struct are passed through 510 | server.Log(...) // calls server.Logger.Log(...) 511 | 512 | // the field name of the embedded type is its type name (in this case Logger) 513 | var logger *log.Logger = server.Logger 514 | ``` 515 | 516 | ## Errors 517 | There is no exception handling. Functions that might produce an error just declare an additional return value of type `Error`. This is the `Error` interface: 518 | ```go 519 | type error interface { 520 | Error() string 521 | } 522 | ``` 523 | 524 | A function that might return an error: 525 | ```go 526 | func doStuff() (int, error) { 527 | } 528 | 529 | func main() { 530 | result, err := doStuff() 531 | if err != nil { 532 | // handle error 533 | } else { 534 | // all is good, use result 535 | } 536 | } 537 | ``` 538 | 539 | # Concurrency 540 | 541 | ## Goroutines 542 | Goroutines are lightweight threads (managed by Go, not OS threads). `go f(a, b)` starts a new goroutine which runs `f` (given `f` is a function). 543 | 544 | ```go 545 | // just a function (which can be later started as a goroutine) 546 | func doStuff(s string) { 547 | } 548 | 549 | func main() { 550 | // using a named function in a goroutine 551 | go doStuff("foobar") 552 | 553 | // using an anonymous inner function in a goroutine 554 | go func (x int) { 555 | // function body goes here 556 | }(42) 557 | } 558 | ``` 559 | 560 | ## Channels 561 | ```go 562 | ch := make(chan int) // create a channel of type int 563 | ch <- 42 // Send a value to the channel ch. 564 | v := <-ch // Receive a value from ch 565 | 566 | // Non-buffered channels block. Read blocks when no value is available, write blocks until there is a read. 567 | 568 | // Create a buffered channel. Writing to a buffered channels does not block if less than unread values have been written. 569 | ch := make(chan int, 100) 570 | 571 | close(ch) // closes the channel (only sender should close) 572 | 573 | // read from channel and test if it has been closed 574 | v, ok := <-ch 575 | 576 | // if ok is false, channel has been closed 577 | 578 | // Read from channel until it is closed 579 | for i := range ch { 580 | fmt.Println(i) 581 | } 582 | 583 | // select blocks on multiple channel operations, if one unblocks, the corresponding case is executed 584 | func doStuff(channelOut, channelIn chan int) { 585 | select { 586 | case channelOut <- 42: 587 | fmt.Println("We could write to channelOut!") 588 | case x := <- channelIn: 589 | fmt.Println("We could read from channelIn") 590 | case <-time.After(time.Second * 1): 591 | fmt.Println("timeout") 592 | } 593 | } 594 | ``` 595 | 596 | ### Channel Axioms 597 | - A send to a nil channel blocks forever 598 | 599 | ```go 600 | var c chan string 601 | c <- "Hello, World!" 602 | // fatal error: all goroutines are asleep - deadlock! 603 | ``` 604 | - A receive from a nil channel blocks forever 605 | 606 | ```go 607 | var c chan string 608 | fmt.Println(<-c) 609 | // fatal error: all goroutines are asleep - deadlock! 610 | ``` 611 | - A send to a closed channel panics 612 | 613 | ```go 614 | var c = make(chan string, 1) 615 | c <- "Hello, World!" 616 | close(c) 617 | c <- "Hello, Panic!" 618 | // panic: send on closed channel 619 | ``` 620 | - A receive from a closed channel returns the zero value immediately 621 | 622 | ```go 623 | var c = make(chan int, 2) 624 | c <- 1 625 | c <- 2 626 | close(c) 627 | for i := 0; i < 3; i++ { 628 | fmt.Printf("%d ", <-c) 629 | } 630 | // 1 2 0 631 | ``` 632 | 633 | ## Printing 634 | 635 | ```go 636 | fmt.Println("Hello, 你好, नमस्ते, Привет, ᎣᏏᏲ") // basic print, plus newline 637 | p := struct { X, Y int }{ 17, 2 } 638 | fmt.Println( "My point:", p, "x coord=", p.X ) // print structs, ints, etc 639 | s := fmt.Sprintln( "My point:", p, "x coord=", p.X ) // print to string variable 640 | 641 | fmt.Printf("%d hex:%x bin:%b fp:%f sci:%e",17,17,17,17.0,17.0) // c-ish format 642 | s2 := fmt.Sprintf( "%d %f", 17, 17.0 ) // formatted print to string variable 643 | 644 | hellomsg := ` 645 | "Hello" in Chinese is 你好 ('Ni Hao') 646 | "Hello" in Hindi is नमस्ते ('Namaste') 647 | ` // multi-line string literal, using back-tick at beginning and end 648 | ``` 649 | 650 | # Snippets 651 | 652 | ## HTTP Server 653 | ```go 654 | package main 655 | 656 | import ( 657 | "fmt" 658 | "net/http" 659 | ) 660 | 661 | // define a type for the response 662 | type Hello struct{} 663 | 664 | // let that type implement the ServeHTTP method (defined in interface http.Handler) 665 | func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) { 666 | fmt.Fprint(w, "Hello!") 667 | } 668 | 669 | func main() { 670 | var h Hello 671 | http.ListenAndServe("localhost:4000", h) 672 | } 673 | 674 | // Here's the method signature of http.ServeHTTP: 675 | // type Handler interface { 676 | // ServeHTTP(w http.ResponseWriter, r *http.Request) 677 | // } 678 | ``` 679 | --------------------------------------------------------------------------------