[置顶] Golang 学习摘录(一)

Golang 学习摘录(一)

  1. 学过C,python,或者Java之类语言再来学习golang应该是无压力,看看语法就能写。语法上比较特殊的如下:

    • 声明变量并赋值使用 :=

      a, b := 1, 2 //声明变量a,b,并且赋值1,2

      a = 2 //a赋值2

    • if 不需要圆括号,并且可以执行表达式.for语句类似

      if x:=1; x<2 {

      }

    • String()函数<同java的toString(),对象的字符串形式>中如果有对自身的"%s"操作,将导致无穷递归调用。因为"%s"会调用String(),将对象转化为字符串形式。

      type MyString string

      func (m MyString) String() string {

          return fmt.Sprintf("MyString=%s", m) // Error: will recur forever.
          return fmt.Sprintf("MyString=%s", string(m)) // OK: note conversion.
      

      }

      string(m)将m转化为一个String对象,然后“%s”是作用在该String对象上,不是m本身,所以不回导致无穷递归

  2. defer有点finally的味道,但是又有不同

    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d ", i)
    }
    

    Deferred functions are executed in LIFO后进先出<栈> order, so this code will cause 4 3 2 1 0

    func trace(s string) string {
        fmt.Println("entering:", s)
        return s
    }
    func un(s string) {
        fmt.Println("leaving:", s)
    }
    func a() {
        defer un(trace("a"))
        fmt.Println("in a")
    }
    func b() {
        defer un(trace("b"))
        fmt.Println("in b")
        a()
    }
    func main() {
        b()
    }

    The arguments to the deferred function (which include the receiver if the function is a method) areevaluated when the defer executes, not when the call executes.

    defer语句执行时,立即计算被defer的函数所需要的所有参数,而不是等到被defer的函数执行才计算该函数的参数。结果如下

    entering: b
    in b
    entering: a
    in a
    leaving: a
    leaving: b
    
  3. new and make

    new(T) returns a pointer to a newly allocated zero value of type T。new适合初始化0值对象,new(File) and &File{} are equivalent。new([]int) returns a pointer to a newly allocated, zeroed slice structure, that is, a pointer to a nil slice value.

    make(T, args) creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T)

  4. Arrays

    Arrays are values. Assigning one array to another copies all the elements. 数组不是引用,是值,数组a赋值给b,直接拷贝成另一份b,结果是数组a,b独立,内容相同

    In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it. 数组作为参数,传递的也是整个数组的值的拷贝,而不是指针

    以上两点与C语言不同,每次拷贝数组代价昂贵,如果希望类似C语言,可以传递指针。

  5. Slices

    Slices行为才与C的数组一致,是指针传递。Slices更常用。Slices底层是数组,只要不超过底层数组的容量,Slices地址不变。一旦添加元素导致超过底层数组的容量,就会reallocated重新分配。默认底层数组容量为cap(slice)。

  6. 特殊语法...(三个点的省略号)

    x := []int{1,2,3}

    y := []int{4,5,6}

    x = append(x, y...)//去掉...报错,因为y不是int类型

    fmt.Println(x)//有点类似Python对于字典**dict

  7. init函数

    每个源代码文件都可以有一个init函数,在该源代码文件的import语句执行完后,并且变量调用其initializers后执行init函数。一般用于检查该文件中的各种状态是否正确

  8. import for side effect

    有时候import一个library,并不是为了使用某个函数或者类,仅仅只是希望该library的init函数执行一次,做一下准备工作:

    import _ "net/http/pprof"//during its init function, the net/http/pprof package registers HTTP handlers that provide debugging information
    
  9. Channel

    管道常用于goroutine之间的通信,同步;Go不推荐使用共享内存,互斥元等方式通信。管道用于goroutine同步例子:

    c := make(chan int)  // 初始化一个不带缓存的管道
    go func() {
        list.Sort()
        c <- 1  // Send a signal; value does not matter.
    }()
    //新起一个goroutine,去做排序,排序完后向管道写入数据
    doSomethingForAWhile()
    <-c   // 阻塞等待管道有数据写入,即等待上面goroutine排序完成
    

    管道用作semaphore(信号量),比如限流,例子:

    var sem = make(chan int, 100)
    func Serve(queue chan *Request) {
    for req := range queue {
        tmp := req // Create new instance of req for every goroutine.
        sem <- 1  //信号量满时写入阻塞
        go func() {
            process(tmp)
            <-sem  //处理完一个请求释放一次信号量
        }()
    }
    }

    由于管道sem分配了buffer,size为100.所以前100个请求,可以不阻塞立即得到执行。后面的请求必须排队等待前面100个请求当中,有请求处理完毕(管道中有数据被读出),才能写入管道,得到处理。所以,这个例子,管道起到限流作用:并行处理的请求数不得超过100

  10. panic recover

    Go的异常处理机制,同try...except...

    Because recover always returns nil unless called directly from a deferred function, deferred code can call library routines that themselves use panic and recover without failing.

    func safelyDo(work *Work) {
    defer func() {
        if err := recover(); err != nil {
            log.Println("work failed:", err)
        }
    }()
    do(work)
    }

    do函数里出了panic异常,执行deferred函数func,func函数里,调用recover捕获异常。

你可能感兴趣的:(golang)