A Tour of Go

本文所参考的资料包含

Packages, variables and functions

  1. fmt表示format的缩写,其中包含了格式化输入输出相关的函数

  2. 在函数中,如果连续的变量均为同类型,那么可以只定义最后一个变量的类型

  3. What is the difference between := and = in Go?

    := 前者将会包含有变量创建的部分,如果左边的变量已经存在,那么直接赋值,否则先创建再赋值

    = 只能完成赋值部分,不包含变量的创建部分

    同时,var 单独完成变量的创建任务

  4. 在package scope中,每条语句必须由关键字开头,如var, func等,也就是说,在这里无法使用short variable declaration

  5. Go中的基本类型包括

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    bool

    string

    int int8 int16 int32 int64
    uint uint8 uint16 uint32 uint64 uintptr

    byte // alias for uint8

    rune // alias for int32
    // represents a Unicode code point

    float32 float64

    complex64 complex128
  6. 每一个变量在被声明之后,默认为zero value,并且不同类型的zero value不同

    • 0 for numeric types,
    • false for the boolean type, and
    • "" (the empty string) for strings.
  7. Go是强类型语言,不支持隐式类型转换

Flow control statement: for, if, else, switch and defer

  1. for loop
    • 不同于C, Java中的for循环,此处不需要添加括号
    • Go中只存在这一种循环结构
    • 后面必须添加{}对循环语句进行包围,不可以省略
  2. defer 关键字,通过压栈的方法将相关语句顺序压入栈中,当同级的语句执行完毕之后,按照栈顺序执行defer 的语句

More types: structs, slices, and maps

  1. slicing是一种数据结构,并且每次切片,不是创建了一个新的变量,只是对原有数组的遍历方式发生了改变

    同时,可以对slicing literal进行多次切片,每次切片都是对最原始的数组的切片

    len(s) 获得切片的当前长度

    cap(s) 获得切片的最大长度

    空切片的zero valuenil

  2. 这里特别区分一下len方法以及cap方法

    前者表示当前切片对应的元素个数,仅仅与slicing时给定的上边界与下边界有关

    后者更偏向于描述了原数组的信息,表示根据当前的切片起点,遍历到原数组的最后一个元素,在切片数组中的下标

Methods and interfaces

  1. Go中不含有类,但是可以针对结构体定义方法

    语法中,只需要在func 以及 方法名之间,指定receiver argument

    a method is just a function with a receiver argument.

  2. 关于receiver存在两种类型,分别是指针类型以及值类型,很明显,前者可以直接对传入的参数进行修改,而后者不可以

    With a value receiver, the Scale method operates on a copy of the originalVertex value. (This is the same behavior as for any other function argument.) The Scale method must have a pointer receiver to change the Vertex value declared in the main function.

  3. 对于receiver类型为指针的方法,通过非指针类型对象调用方法是可以的,Go将会自动将v.Scale(10)转化为&v.Scale(10);但是对于接受参数类型为指针的函数而言,必须传入指定类型的变量。

  4. 对于receiver为值类型的方法,每次调用会有一次copy,将当前结构体中的数据copy入一个新建的结构体对象,之后在该对象上调用方法,因此如果多次使用值传递的方法,那么程序的性能不会很好

  5. 接口定义了一些通用的方法

    在Go中,可以定义接口类型的变量,该变量可以指向任何实现了接口中定义的全有方法的结构体

    需要注意的是,由于方法的receiver含有值传递、指针传递两种,因此如果结构体中的方法只定义了指针类型的,那么对接口进行赋值时,也只能赋值指针类型的结构体

  6. 通过assertion方法,可以将接口中存储的对象提取出来

    注意assertion方法有两个返回值,第一个用于存储对应变量,第二个返回是否成功

    eg. f, ok := i.(float64)

  7. 一个空接口可以用来表示任意类型的结构体或者自带类型的变量

  8. 通过type switches可以方便地判断接口变量中存储的变量类型,并且根据不同的情况定义不同的行为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package main

    import "fmt"

    func do(i interface{}) {
    switch v := i.(type) {
    case int:
    fmt.Printf("Twice %v is %v\n", v, v*2)
    case string:
    fmt.Printf("%q is %v bytes long\n", v, len(v))
    default:
    fmt.Printf("I don't know about type %T!\n", v)
    }
    }

    func main() {
    do(21)
    do("hello")
    do(true)
    }
    1
    2
    3
    Twice 21 is 42
    "hello" is 5 bytes long
    I don't know about type bool!
    • 特殊接口 — Stringer

      1
      2
      3
      type Stringer interface {
      String() string
      }

      该接口类似于Python中的__str__(self)方法,在直接print变量的时候,将会执行该方法,便于进行调试

    • 特殊接口 — error

      1
      2
      3
      type error interface {
      Error() string
      }

      每次函数调用,尽力那个返回两个值,第一个为正确执行返回的值,第二个为程序的执行结果是否合法

    • 特殊接口 — io.Reader,其中包含有一个方法 func (T) Read(b []byte) (n int, err error)

      Read populates the given byte slice with data and returns the number of bytes populated and an error value. It returns an io.EOF error when the stream ends.

      可以认为这是一个输入流,传入字节类型的数组,方法返回之后,n表示其中已经被填写的字节数

    Concurrency

    1. 通过关键字go来开启协程

    2. 特性 — select

      通过该关键字,可以很轻松地实现,多个协程在执行完毕之后,才可以执行的协程,定义这样的拓扑关系;在多个同级别协程中,随机地选择一个可以执行的协程 eg.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      package main

      import "fmt"

      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
      }
      }
      }

      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)
      }
    3. 给定一棵二叉树,编写一个遍历其中的所有结点,并且将结点信息输入通道的函数

      注意 这里在启动协程的时候,妥善处理了发送者主动关闭通道的行为

      只有这样,后面在取元素的时候,第二个标志位ok才有效

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      package main

      import "golang.org/x/tour/tree"
      import "fmt"

      /*
      type Tree struct {
      Left *Tree
      Value int
      Right *Tree
      }
      */

      // Walk walks the tree t sending all values
      // from the tree to the channel ch.
      func Walk(t *tree.Tree, ch chan int) {
      if t == nil {
      return
      }
      ch <- t.Value
      if t.Left != nil {
      Walk(t.Left, ch)
      }
      if t.Right != nil {
      Walk(t.Right, ch)
      }
      }

      func main() {
      ch := make(chan int)
      t := tree.New(1)
      go func() {
      Walk(t, ch)
      close(ch)
      }()

      for {
      val, ok := <- ch
      if ok == false {
      break
      } else {
      fmt.Println(val)
      }
      }
      }

How to write Go code

  1. Go文件的存储主要分为两个部分,分别是

    • bin文件夹

      用于存储编译好的可执行文件,在配置好环境变量之后,如果存在这样的一个可执行文件bin/hello

      那么在命令行中只需要键入hello即可运行该文件

    • src文件夹

      源代码文件,主要包含有三部分: 包文件(package source)、命令文件(command source)、测试文件test source

  2. 通过go install命令进行编译,生成可执行文件到bin文件夹

    需要注意的是,存在所谓的base path,也就是说,在install的时候,要么从src文件夹中执行该命令;要么直接进入最底层的源代码文件夹,直接go install

    base path也适用于引用其他包

  3. 对于每一个源代码文件,在名称后面加上xx_test.go,并且在其中编写测试用例,就可以完成测试功能

    执行命令为go test,使用方法同go install

0%