Go语言编程

语言特性

  • 自动垃圾回收(GC)
    所谓垃圾回收,即所有的内存分配动作都会被在运行时记录,同时任何对该内存的使用也都会被记录,然后垃圾回收器会对所有已经分配的内存进行跟踪监测,一旦发现有些内存已经不再被任何人使用,就阶段性地回收这些没人用的内存。

  • 更丰富的内置类型
    字典类型(map)数组切片(Slice)。可以认为数组切片是一种可动态增长的数组。

  • 函数多返回值

  • 错误处理: defer, panic, recover

  • 匿名函数和闭包

  • 类型和接口

  • 并发编程
    goroutine是一种比线程更加轻盈、更省资源的协程。Go语言通过系统的线程来多路派遣这些函数的执行,使得每个用go关键字执行的函数可以运行成为一个单位协程。当一个协程阻塞的时候,调度器就会自动把其他协程安排到另外的线程中去执行,从而实现了程序无等待并行化运行。此外,由于一个进程内创建的所有goroutine运行在同一个内存地址空间中,因此如果不同的goroutine不得不去访问共享的内存变量,访问前应该先获取相应的读写锁。Go语言标准库中的sync包提供了完备的读写锁功能。

package main

import "fmt"

func sum(values []int, resultChan chan int) {
    sum := 0
    for _, value := range values {
        sum += value
    }

    resultChan <- sum // 将计算结果发送到channel中
}

func main() {
    values := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    resultChan := make(chan int, 2)

    go sum(values[:len(values)/2], resultChan)
    go sum(values[len(values)/2:], resultChan)

    sum1, sum2 := <-resultChan, <-resultChan // 接收结果

    fmt.Println("Result:", sum1, sum2, sum1+sum2)
}
  • 反射
  • 语言交互性
    在Go代码中,可以按Cgo的特定语法混合编写C语言代码。

Go语言还提供了一个关键字range,用于便捷地遍历容器中的元素。

for i, v := range array {
    fmt.Println("Array element[", i, "]=", v)
}
mySlice = append(mySlice, 1, 2, 3)
mySlice2 := []int{8, 9, 10}
// 给mySlice后面添加另一个数组切片
mySlice = append(mySlice, mySlice2...)

需要注意的是,第二个参数mySlice2后面加了三个点,如果没有这个省略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相当于把mySlice2包含的所有元素打散后传入。


在有返回值的函数中,不允许将“最终的”return语句包含在if...else...结构中,否则会编译失败:
function ends without a return statement
失败的原因在于,Go编译器无法找到终止该函数的return语句。编译失败的案例如下:

func example(x int) int {
  if x == 0 {
      return 5
  } else {
      return x
  }
}

可以不设定switch之后的条件表达式,在此种情况下,整个switch结构与多个if...else...的逻辑作用等同。

switch {
   case 0 <= Num && Num <= 3:
      fmt.Printf("0-3")
  case 4 <= Num && Num <= 6:
      fmt.Printf("4-6")
  case 7 <= Num && Num <= 9:
      fmt.Printf("7-9")
}

func myfunc(args ...int) {
   for _, arg := range args {
      fmt.Println(arg)
   }
}

这段代码的意思是,函数myfunc()接受不定数量的参数,这些参数的类型全部是int。形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。


闭包

package main

import (
    "fmt"
)

func main() {
    i := 1

    a := func() func() {
        j := 2

        return func() {
            fmt.Println("i,j:", i, j)
        }
    }

    a()()

    i = 10

    a()()
}

在变量a指向的闭包函数中,只有内部的匿名函数才能访问变量j,而无法通过其他途径访问
到,因此保证了i的安全性。


在Go语言中数组是一个值类型(value type)。所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。

所有的Go语言类型(指针类型除外)都可以有自己的方法。

在Go语言中,未进行显式初始化的变量都会被初始化为该类型的零值,例如bool类型的零值为false,int类型的零值为0,string类型的零值为空字符串。

要使某个符号对其他包(package)可见(即可以访问),需要将该符号定义为以大写字母开头。需要注意的一点是,Go语言中符号的可访问性是包一级的而不是类型一级的。


Mutex

所有在 Lock 和 Unlock 之间的代码,都只能由一个 Go 协程执行。

package main

import (
    "fmt"
    //"sync"
    "time"
)

//var lock sync.Mutex
var x int = 0

func main() {
    for i := 0; i < 1000; i++ {
        go add()
    }

    time.Sleep(1e9)
    fmt.Println(x)
}

func add() {
    //lock.Lock()
    x += 1
    //lock.Unlock()
}
输出:
970

用channel实现Mutex

package main

import (
    "fmt"
    "time"
)

var x int = 0

func main() {
    ch := make(chan bool, 1)

    for i := 0; i < 1000; i++ {
        go add(ch)
    }

    time.Sleep(1e9)
    fmt.Println(x)
}

func add(ch chan bool) {
    ch <- true
    x += 1
    <-ch
}
输出:
1000

全局唯一性操作

package main

import (
    "fmt"
    "sync"
    "time"
)

var x int = 0
var once sync.Once

func main() {

    for i := 0; i < 1000; i++ {
        go ADD()
    }

    time.Sleep(1e9)
    fmt.Println(x)
}

func add() {
    x += 1
}

func ADD() {
    once.Do(add)
}
输出:
1

Marshal and Unmarshal

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

func main() {
    type student struct {
        ID     int
        Name   string
        Colors []string
    }

    jthe := student{
        ID:    21116,
        Name:   "Hejtao",
        Colors: []string{"blue", "red", "black"},
    }

    b, err := json.Marshal(jthe)
    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stdout.Write(b)
}
输出:
{"ID":21116,"Name":"Hejtao","Colors":["blue","red","black"]}
package main 
import ( 
    "encoding/json" 
    "fmt" 
) 
func main () { 
    var jsonBlob = []byte ( ` [ 
        { "Name" : "Platypus" , "Order" : "Monotremata" } , 
        { "Name" : "Quoll" ,     "Order" : "Dasyuromorphia" } 
    ] ` ) 
    type Animal struct { 
        Name  string 
        Order string 
    } 
    var animals []Animal 
    err := json. Unmarshal (jsonBlob , &animals) 
    if err != nil { 
        fmt. Println("error:" , err) 
    } 
    fmt. Printf("%+v" , animals) 
}
输出:
[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

你可能感兴趣的:(Go语言编程)