Go语言基础速刷手册

我们就不从安装和hello world开始了,首先来看下Go的变量和内置数据类型都有哪些。

变量声明

Go 语言与其他语言显著不同的一个地方在于,Go 语言的类型在变量后面。

方法一:指定变量类型,如果没有初始化,则变量默认为零值。

var a = "Agong"var b intvar c boolvar d string

这里的零值指的是:数值类型为0、布尔类型为false、空字符串等。

方法二:根据值自行判定变量类型。

var d = true

方法三:在函数体内需要初始化声明时使用:=(不可以用于全局变量的声明与赋值)

msg := "Hello World!"

 

数据类型

空值:nil  以下几种类型为nil

var a *intvar a []intvar a map[string] intvar a chan intvar a func(string) intvar a error // error 是接口

整型类型:int

浮点数类型:float32、float64

字节类型:byte

字符串类型:string

布尔值类型:bool(true或false)

在Go语言中,字符串使用UTF8编码,如果是英文每个字符占1byte;如果是中文,一般占3字节。string是一个不可变的byte切片。

package string_testimport (  "reflect"  "testing")func TestString(t *testing.T) {  var s string  // 空字符串  t.Log(s)  s = "hello你好"  t.Log(s, len(s)) // hello你好 11  s = "中"  t.Log(len(s))  // 3 是byte数  //s[1] = '3'// string 是一个不可变的byte切片  c := []rune(s)  // 将string字符串转为rune数组  t.Log(len(c))  // 1  t.Logf("中 unicode %x", c[0]) // 中 unicode 4e2d  t.Logf("中 UTF8 %x", s)  // 中 UTF8 e4b8ad  t.Log(reflect.TypeOf(s).Kind())  //string}

reflect.TypeOf().Kind()可以知道某个变量的类型;

[]rune表示将string转为rune数组。

 

数组(array)和切片(slice)

声明数组

var arr [10] int  // 一维var arr1 [5][5] int  // 二维

初始化声明

var arr = [5]int{1, 2, 3, 4, 5}// 或 arr := [5]int{1, 2, 3, 4, 5}

使用索引修改数组

func main()  {  arr := [5] int{1, 2, 3, 4, 5}  for i := 0; i < len(arr); i++{    arr[i] += 100  }  fmt.Println(arr)  // [101 102 103 104 105]}

由于数组长度不能改变如果想拼接2个数组,或是获取子数组,需要使用切片。

切片使用数组作为底层结构,包含三个组件:容量,长度和指向底层数组的指针,切片可以随时进行扩展。

 

声明切片

func TestSlice(t *testing.T)  {  slice1 := make([]float32, 0) // 长度为0的切片  slice2 := make([]float32, 3, 5)  // [0 0 0] 长度为3容量为5的切片  fmt.Println(len(slice1))  // 0  fmt.Println(len(slice2), cap(slice2))  // 3 5}

使用切片

func TestSlice(t *testing.T)  {  slice2 := make([]float32, 3, 5)  // [0 0 0] 长度为3容量为5的切片  slice2 = append(slice2, 1, 2, 3, 4)  t.Log(len(slice2), cap(slice2), slice2)  // 7 12 [0 0 0 1 2 3 4]  // 子切片  sub1 := slice2[3:]  //[1 2 3 4]  sub2 := slice2[:3]  //[0 0 0]  // 合并切片  combined := append(sub1, sub2...)   t.Log(combined)  // [1 2 3 4 0 0 0]}

sub2... 表示将切片解构为 N 个独立的元素。

 

字典(键值对,map)

map类似于Python的dict,是一种存储键值对(Key-Value)的数据结构。

func Test(t *testing.T)  {  // 仅声明  m1 := make(map[string]int)  // 声明时初始化  m2 := map[string]string{    "Jack": "Male",    "Rose": "Female",  }  // 赋值/修改  m1["Tom"] = 20  t.Log(m1, m2)  // map[Tom:20] map[Jack:Male Rose:Female]}

遍历map

func TestTravelMap(t *testing.T)  {  m1 := map[int]int{1: 2, 2: 4, 3: 9}  for k, v := range m1{    t.Log(k, v)  }}//3 9//1 2//2 4

 

指针(pointer)

一个指针变量指向了一个值的内存地址,声明时使用符号*指明该变量为指针;对于已存在的变量,使用符号&获取该变量地址。

package mainimport "fmt"func main()  {  var a int = 20  //声明实际变量  var ip *int  // 声明指针变量  ip = &a  // 指针变量的存储地址  fmt.Printf("a 变量的地址是:%x\n", &a)  /*指针变量的存储地址*/  fmt.Printf("ip变量存储的指针地址:%x\n", ip)  /*使用指针访问值*/  fmt.Printf("*ip变量的值:%d\n", *ip)}//a 变量的地址是:c00000a098//ip变量存储的指针地址:c00000a098//*ip变量的值:20

一般来说,指针通常在函数传递参数,或者给某个类型定义新的方法时使用。Go语言中参数是按值传递的,如果不使用指针,函数内部会拷贝一份参数的副本,对参数的修改并不会影响到外部变量的值。如果使用指针,则会影响外部变量的值。

package mainimport "fmt"func add(num int)  {  num += 1}func realAdd(num *int)  {  *num += 1}func main()  {  num := 100  add(num)  fmt.Println(num)  // 100 num没有变化  realAdd(&num)  fmt.Println(num)  // 101 指针传递 num被修改}

在某种情况下,我们需要保存数组,我们就需要用到指针。

const MAX = 3  // MAX为常量func main()  {  a := []int{10, 100, 200}  var i int  var ptr [MAX] *int  for i = 0; i < MAX; i++{    ptr[i] = &a[i]  // 整数地址赋值给指针数组  }  for i = 0; i < MAX; i++{    fmt.Printf("a[%d] = %d\n", i, *ptr[i])  }}//a[0] = 10//a[1] = 100//a[2] = 200

 

流程控制(if, for, switch, select)

条件语句if else

func TestIfElse(t *testing.T)  {  age := 18  if age < 18 {  //可以简写为 if age := 18; age < 18{}    t.Log("Kid")  }else {  // 注意else需要和if的}在同一行    t.Log("Adult")  }}

switch

func TestSwitch(t *testing.T)  {  type Gender int8  const (    MALE Gender = 1    FEMALE Gender = 2  )  gender := MALE  switch gender {  case MALE:    t.Log("Male")    //fallthrough  case FEMALE:    t.Log("Female")    //fallthrough  default:    t.Log("Unknown")  }}// Male

这里使用了type关键字定义了一个新的类型Gender,使用const定义了MALE 和 FEMALE 2 个常量。Go 语言的 switch 不需要 break,匹配到某个 case,执行完该 case 定义的行为后,默认不会继续往下执行。如果需要继续往下执行,需要使用 fallthrough。

case后还支持多种条件:

func TestSwitchMultiCase(t *testing.T)  {  for i:=0; i<5; i++{    switch i {    case 0, 2:  //case后支持多项判断      t.Log(i, "It is Even")    case 1, 3:      t.Log(i, "It is Odd")    default:      t.Log(i, "It is not in 0-3")    }  }}//0 It is Even//1 It is Odd//2 It is Even//3 It is Odd//4 It is not in 0-3

for

对数组(arr)、切片(slice)、字典(map) 使用 for range 遍历:

func TestForRange(t *testing.T)  {  // 遍历数组  nums := []int{10, 20, 30, 40}  for _, num := range nums{    t.Log(num)  }  //10  //20  //30  //40    // 遍历字典  m2 := map[string]string{    "Jack": "Male",    "Rose": "Female",  }  for k, v := range m2{    t.Log(k, v)  }  //Jack Male  //Rose Female}

由于在Go语言中只有用for关键字来控制循环,那如何实现while循环的效果呢

func TestWhileLoop(t *testing.T) {  n := 0  for n < 5 {    t.Log(n)    n++  }}//0//1//2//3//4

select

select是Go中的一个控制语句,每个case必须是一个通信操作,要么是发送要么接收。select 会循环检测条件,如果有满足则执行并退出,否则一直循环检测。(以下例子中的channel之后会说到)

func TestSelect(t *testing.T) {  var c1, c2, c3 chan int  var i1, i2 int  select {    case i1 = <-c1:      fmt.Print("received", i1, "from c1\n")    case c2 <- i2:      fmt.Print("sent", i2, "to c2\n")    case i3, ok := <-c3:      if ok{        fmt.Print("receive", i3, "from c3\n")      } else {        fmt.Print("c3 is closed\n")      }    default:      fmt.Print("no communication\n")  }}//no communication

 

函数(func)

一个函数使用关键字func定义,参数可以有多个,返回值也可以有多个。package main中的func main()约定为可执行程序的入口。

func funcName(param1 Type1, param2 Type2, ...) (return1 Type3, ...) {    // body}
package mainimport "fmt"func max(num1, num2 int) int  {  /*声明局部变量*/  var result int  if num1 > num2{    result = num1  }  if num1 < num2{    result = num2  }  return result}func main()  {  /*定义局部变量*/  var a int = 100  var b int = 200  var res int  /*调用函数并返回最大值*/  res = max(a, b)  fmt.Printf("最大值是:%d\n", res)}//最大值是:200

 

错误处理

函数在实现过程中,如果出现不能处理的错误,可以返回给调用者处理,比如调用标准库的os.open读取文件,os.open有2个返回值,第一个是*file,第二个是error,如果调用成功error的值是nil;如果失败,例如文件不存在,可以通过error知道具体的错误信息。

error类型是一个接口类型,以下为error定义:

type error interface {    Error() string}
package mainimport (  "fmt"  "os")func main()  {  _, err := os.Open("filename.txt")  if err != nil{    fmt.Println(err)  }}//open filename.txt: The system cannot find the file specified.

使用error.New返回自定义的错误

func hello(name string) error {  if len(name) == 0{    return errors.New("error: name is null")  }  fmt.Println("Hello", name)  return nil}func main()  {  if err := hello(""); err != nil{    fmt.Println(err)  }}//error: name is null

error往往是能预知的错误但是也可能出现一些不可预知的错误,例如数组越界,这种错误可能会导致程序非正常退出,在 Go 语言中称之为 panic。

package mainimport "fmt"func get(index int) int {  arr := [3]int{2, 3, 4}  return arr[index]}func main()  {  fmt.Println(get(5))  fmt.Println("finished")}//panic: runtime error: index out of range [5] with length 3//goroutine 1 [running]://Process finished with the exit code 2

panic用于主动抛出错误,recover用来捕获panic抛出的错误。发生panic后,程序会从调用panic的函数位置或发生panic的地方立即返回,逐层向上执行函数的defer语句,然后逐层打印函数调用堆栈,直到被recover捕获或运行到最外层函数。defer 和 recover类似于Python中的try...catch。

 

recover用来捕获panic,阻止panic继续向上传递。recover()和defer一起使用,但是defer只有在后面的函数体内直接被掉用才能捕获panic来终止异常,否则返回nil,异常继续向外传递。

func get(index int) (ret int) {  defer func() {    if r := recover(); r != nil {      fmt.Println("Some error happened!", r)      ret = -1    }  }()  arr := [3] int{2, 3, 4}  return arr[index]}func main()  {  fmt.Println(get(5))  fmt.Println("finished")}//Some error happened! runtime error: index out of range [5] with length 3//-1//finished

 

  • 在 get 函数中,使用 defer 定义了异常处理的函数,在协程退出前,会执行完 defer 挂载的任务。因此如果触发了 panic,控制权就交给了 defer。

  • 在 defer 的处理逻辑中,使用 recover,使程序恢复正常,并且将返回值设置为 -1,在这里也可以不处理返回值,如果不处理返回值,返回值将被置为默认值 0。

 

结构体,方法和接口

结构体(struct)

结构体类似于其他语言的class,是一个由相同类型或不同类型的数据构成的数据集合。

package mainimport "fmt"type Student struct {  name string  age int}func (stu *Student) hello(person string) string {  return fmt.Sprintf("Hello %s, I am %s", person, stu.name)}func main()  {  stu := &Student{    name: "Jack",  } // 实例化  msg := stu.hello("Rose")  // 调用方法:实例名.方法名(参数)  fmt.Println(msg)}// Hello Rose, I am Jack

 

实现方法与实现函数的区别在于,func 和函数名hello 之间,加上该方法对应的实例名 stu 及其类型 *Student,可以通过实例名访问该实例的字段name和其他方法了。

此外,还可以通过new实例化

func main() {  stu2 := new(Student)  fmt.Println(stu2.hello("Alice")) // hello Alice, I am  , name 被赋予默认值""}

 

接口(interfaces)

一般而言,接口定义了一组方法的集合,接口不能被实例化,一个类型可以实现多个接口。Go 语言中,并不需要显式地声明实现了哪一个接口,只需要直接实现该接口对应的方法即可。

package mainimport "fmt"type Person interface {  getName() string}type Student struct {  name string  age int}func (stu *Student) getName() string {  return stu.name}func (stu *Student) getAge() int {  return stu.age}type Worker struct {  name string  gender string}func (w *Worker) getName() string {  return w.name}func main()  {  var p Person = &Student{    name: "Jack",    age: 24,  }  fmt.Println(p.getName())  //Jack  // 实例可以强制类型转换为接口,接口也可以强制类型转换为实例。  stu := p.(*Student)  fmt.Println(stu.getAge())  //24}

为确保某个类型实现了某个接口的所有方法,可以使用下面的方法进行检测,如果实现不完整,编译期将会报错。

var _ Person = (*Student)(nil)var _ Person = (*Worker)(nil)
  • 将空值 nil 转换为 *Student 类型,再转换为 Person 接口,如果转换失败,说明 Student 并没有实现 Person 接口的所有方法。

空接口

如果定义了一个没有任何方法的空接口,那么这个接口可以表示任意类型。

func main()  {  m := make(map[string]interface{})  m["name"] = "Jack"  m["age"] = 24  m["scores"] = [3] int{90, 97, 92}  fmt.Println(m)  // map[age:24 name:Jack scores:[90 97 92]]}

 

并发编程(goroutine)

goroutine 是轻量级线程,通过 go 关键字即可开启一个新的运行期线程 goroutine 。同一个程序中的所有 goroutine 共享同一个地址空间。

package mainimport (  "fmt"  "time")func say(s string)  {  for i := 0; i < 5; i++{    time.Sleep(100 * time.Millisecond)    fmt.Println(s)  }}func main()  {  go say("world")  say("hello")}//hello//world//world//hello//hello//world//hello//world//hello

执行以上代码,你会看到输出的 hello 和 world 是没有固定先后顺序。因为它们是两个 goroutine 在执行。

 

Go 语言提供了 sync 和 channel 两种方式支持协程(goroutine)的并发。

例如我们希望并发下载 N 个资源,多个并发协程之间不需要通信,那么就可以使用 sync.WaitGroup,等待所有并发协程执行结束。

package mainimport (  "fmt"  "sync"  "time")var wg sync.WaitGroupfunc download(url string)  {  fmt.Println("start to download", url)  time.Sleep(time.Second)  //模拟耗时操作  wg.Done()  //减去一个计数}func main()  {  for i := 0; i < 3; i++  {    wg.Add(1)  //为wg添加一个计数    go download("a.com/" + string(i+'0'))  //启动新的协程并发执行 download 函数  }  wg.Wait()  //等待所有的协程执行结束  fmt.Println("Done!")}//start to download a.com/2//start to download a.com/1//start to download a.com/0//Done!

 

 

通道(channel)

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

ch <- v    // 把 v 发送到通道 chv := <-ch  // 从 ch 接收数据           // 并把值赋给 v

声明通道

ch := make(chan int)

默认情况下,通道是不带缓冲区的。

package mainimport "fmt"func sum(s [] int, c chan int)  {  sum := 0  for _, v := range s{    sum += v  }  c <- sum  //把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)  //-5 17 12}

加入通道缓冲区

ch := make(chan int, 100)

通道遵循先进先出原则。

不带缓冲区的通道是同步的,即在向通道发送值时,必须及时接收,且必须一次接收完成。

而带缓冲区的通道是异步的,它仅会以缓冲区满而阻塞,直到先塞发送到通道的值被从通道中接收才可以继续往通道传值。

func main() {  ch := make(chan int, 2)  ch <- 1  a := <-ch  ch <- 2  ch <- 3  fmt.Println(<-ch)  fmt.Println(<-ch)  fmt.Println(a)}//2//3//1

如上面的例子,最多只能让同时在通道中停放2个值,想多传值,就需要把前面的值提前从通道中接收出去。

我们再将下载资源的例子实现协程之间阻塞等待并发协程返回消息:

var ch = make(chan string, 10) // 创建大小为 10 的缓冲通道func download(url string) {  fmt.Println("start to download", url)  time.Sleep(time.Second)  ch <- url // 将 url 发送给通道ch}func main() {  for i := 0; i < 3; i++ {    go download("a.com/" + string(i+'0'))  }  for i := 0; i < 3; i++ {    msg := <-ch // 等待信道返回消息。    fmt.Println("finish", msg)  }  fmt.Println("Done!")}//start to download a.com/2//start to download a.com/1//start to download a.com/0//finish a.com/2//finish a.com/0//finish a.com/1//Done!

 

包(Package)和模块(Modules)

 

Go语言没有像其它语言一样有public、protected、private等访问控制修饰符,它是通过字母大小写来控制可见性的。区分粒度是包(package)。如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头表示能被其它包访问或调用(相当于public),非大写开头就只能在包内使用(相当于private,变量或常量也可以下划线开头)。

 

参考:

https://golang.org/

https://geektutu.com/post/quick-golang.html

https://www.runoob.com/go/go-tutorial.html

 

CSDN这边更新可能会慢一些。可移步个人日更公众号:才浅的每日python。欢迎各位来交流~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Go 编程语言是一个使得程序员更加有效率的开源项目。Go 是有表 达力、简洁、清晰和有效率的。它的并行机制使其很容易编写多核 和网络应用,而新的类型系统允许构建有性的模块化程序。Go 编译到机器码非常快速,同时具有便利的垃圾回收和强大的运行 时反射。它是快速的、静态类型编译语言,但是感觉上是动态类型 的,解释型语言。 1 简介 1 官方文档 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 前身. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 获得Go . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 在Windows 下获得Go . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2 基础 6 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 编译和运行代码. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 本书使用的设置. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 变量、类型和保留字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 运算符和内建函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Go 保留字. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 控制结构 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 内建函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 array 、slices 和map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3 函数 30 作用域 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 多值返回. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 命名返回值. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 延迟代码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 变参. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 函数作为值. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 回调. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 恐慌(Panic)和恢复(Recover). . . . . . . . . . . . . . . . . . . . . . . 36 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4 包 48 标识符 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 包的文档. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 测试包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 常用的包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 5 进阶 58 内存分配. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 定义自己的类型. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 ----------------------- 页面 5----------------------- ii Chapter: Contents 转换. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 6 接口 70 方法. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 接口名字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 简短的例子. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 7 并发 82 更多关于channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 8 通讯 90 io.Reader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 一些例子 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 命令行参数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 执行命令 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 网络. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 练习. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 答案. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 A 版权 106 贡献者 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 许可证和版权 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 B 索引 108 C Bibliography 110 ListofFigures 1.1 Go 编年史. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2.1 array 与slice 对比 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.1 一个简单的LIFO 栈 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 6.1 使用反射去除层次关系. . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 ListofCodeExamples 2.1 Hello world . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 Declaration with . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3 Declaration with : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.4 Familiar types are still distinct . . . . . . . . . . . . . . . . . . . . . . . . . . 9 ----------------------- 页面 6----------------------- ListofCodeExamples iii 2.5 array 和slice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.6 Simple for loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.7 For loop with an array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.8 Fizz-Buzz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.9 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.10 Runes in strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.11 Reverse a string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.1 函数定义 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.2 递归函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.3 局部作用域 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.4 全局作用域 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.5 当函数调用函数时的作用域. . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.6 没有defer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.7 With defer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.8 函数符号 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.9 带参数的函数符号 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.10 在defer 中访问返回值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 3.11 匿名函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 3.12 使用map 的函数作为值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 3.13 Go 中的平均值函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.14 stack.String() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.15 有变参的函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.16 Go 编写的斐波那契函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 3.17 Map 函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 3.18 冒泡排序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 4.1 A small package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 4.2 even 包的使用. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 4.3 even 包的测试. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 4.4 包里的Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.5 Push/Pop 测试 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.6 逆波兰计算器. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 5.1 Use of a pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.2 获取指针指向的值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.3 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.4 Go 中更加通用的map 函数 . . . . . . . . . . . . . . . . . . . . . . . . . . 67 5.5 cat 程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.1 定义结构和结构的方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 6.2 用空接口作为参数的函数. . . . . . . . . . . . . . . . . . . . . . . . . . . 72 6.3 实现接口失败. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 6.4 扩展内建类型错误 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 6.5 扩展非本地类型错误. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 6.6 使用反射自省. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 6.7 反射类型和值. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 6.8 私有成员的反射 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.9 公有成员的反射 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.10 通用的计算最大值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 7.1 Go routine 实践 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 7.2 Go routines 和channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 7.3 使用select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 7.4 Go 的channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 ----------------------- 页面 7----------------------- iv Chapter: Contents 7.5 添加额外的退出channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 7.6 Go 的斐波那契函数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 8.1 从文件读取(无缓冲) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.2 从文件读取(缓冲). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.3 Processes in Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 8.6 uniq(1) 的Perl 实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.4 Go 中的进程. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 8.5 wc(1) 的Go 实现. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 8.7 uniq(1) 的Go 实现. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 8.8 一个Go quine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 8.9 简易echo 服务器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 8.10 数字游戏 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 8.11 finger 守护进程 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 ListofExercises 1 (1) 文档. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2 (0) For-loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3 (0) FizzBuzz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 4 (1) Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 5 (1) Average . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 6 (0) 平均值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 7 (0) 整数顺序. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 8 (1) 作用域 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 9 (1) 栈 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 10 (1) 变参. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 11 (1) 斐波那契. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 12 (1) Map function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 13 (0) 最小值和最大值. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 14 (1) 冒泡排序. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 15 (1) 函数返回一个函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 16 (0) stack 包. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 17 (2) 计算器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 18 (1) 指针运算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 19 (2) 使用interface 的map 函数 . . . . . . . . . . . . . . . . . . . . . . . . . 65 20 (1) 指针. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 21 (1) 链表. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 22 (1) Cat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 23 (2) 方法调用. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 24 (1) 接口和编译 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 25 (1) 指针和反射 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 26 (2) 接口和max() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 27 (1) Channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 28 (2) 斐波那契II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 29 (2) 进程. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 30 (0) 单词和字母统计. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 31 (0) Uniq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 32 (2) Quine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 33 (1) Echo 服务. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 ----------------------- 页面 8----------------------- ListofExercises v 34 (2) 数字游戏. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 35 (1) *Finger 守护进程. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值