首页 » Go » 正文

Go 语言集训(一)

编程基本概念

  1. 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
  2. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
  3. 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
  4. 线程进程都是同步机制,而协程则是异步

编程基础

package Traininig


func varFunc() {
    var v1 int
    var v2 string
    var v3 [10]int //数组
    var v4 []int   // 数组切片
    var v5 struct {
        f int
    }
    var v6 *int           //指针
    var v7 map[string]int //map,key为string,value是int类型
    var v8 func(a int) int
    var (
        v1 int
        v2 string
    )

    var v1 int = 10 //正确方式1
    var v2 = 10     //正确方式2,编译器自动推导出v2的类型
    v3 := 10        //正确方式3,编译器自动推导出v3的类型

    var i int
    i := 2 //出错!

    var v10 int
    v10 = 100

    i, j = j, i

    _, _, nikcname := GetName()

    // -12
    // 3.1415926 浮点类的常量
    // 3.2+12i 复数类型的常量
    // true 布尔类型的常量
    // "foo" 字符串常量
    // -12l -12的long类型
    const Pi float64 = 3.141592658
    const zero = 0.0 //无类型浮点常量
    const (
        size int64 = 1024
        eof        = -1 //无类型整形常量
    )
    const u, v float32 = 0, 3   //u=0.0. v=3.0 常量的多赋值
    const a, b, c = 3, 4, "foo" //无类型整型和字符串常量
    const mask = 1 << 3
    const Home = os.GetEnv("HOME")

    const ( //iota被强制重置为0
        c0 = iota // c0 = 0
        c1 = iota // c1 = 1
        c2 = iota // c2 = 2
    )

    const (
        a = 1 << iota //iota被重置为0,这时候a = 1 << 0 = 1
        b = 1 << iota //b = 1 << 1 = 2
        c = 1 << iota // c = 1 << 3 = 4
    )

    const (
        u         = iota * 24 // u = 0
        v float64 = iota * 42 // v = 42.0
        w         = iota * 42 // w = 84
    )

    const x = itoa // iota 被强制重置为0
    const y = itoa // iota 被强制重置为0

    const (
        c0 = itoa // c0 = 0
        c1        // c1 = 1
        c2        // c2 = 2
    )

    const (
        a = 1 << iota // a=1
        b             // b=2
        c             // c=4
    )

    const (
        Sunday = iota
        Monday
        Tuesday
        Wendesday
        Thursday
        Friday
        Saturday
        numberofDays //这个是私有变量,包外面看不到,因为是小写的
    )

    var v1 bool
    v1 = true
    v2 := false
    v3 := (1 == 2) //v2也会被推导为bool类型

    var b bool
    b = 1       //编译错误
    b = bool(1) //编译错误 bool不支持自动或者强制的类型转换

    var value2 int32
    value1 := 32           //value1被默认推动到int类型
    value2 = value1        //编译错误,因为int和int32 在go中属于不同的类型
    value2 = int32(value1) //编译通过,强制类型转化

    mod := (5 % 3) // mod = 2

    i, j = 1, 2
    if i == j {
        fmt.Println("i and j are equal")
    }

    var i int32
    var j int64
    i, j = 1, 2
    if i == j { //编译出错,两个不同类型的整型数不能直接比较
        fmt.Println("i and j are equal")
    }
    if i == 1 || j == 2 { //编译通过,但能与字面变量(literal)进行比较
        fmt.Println("i and j are equal")
    }

    var fvalue1 float32
    fvalue1 = 12
    fvalue2 := 12.0 //必须添加.0 不然会被推导为整形,并且默认为float64,C语言中的double
    fvalue2 = float64(fvalue1)

    var value1 complex64 //由2个float32构成的复数
    value1 = 3.2 + 12i
    value2 := 3.2 + 12i
    value3 := complex(3.2, 12)

    var str string
    str = "hello world"
    ch := str[0]
    fmt.Printf("The length of \"%s\" is %d", str, len(str))
    fmt.Printf("The fist character of \"%s\" is %c.\n", str, ch)
    str[0] = "H" //编译错误

    str := "Hello,世界"
    n := len(str)
    for i := 0; i < n; i++ {
        ch := str[i]      //以字符数组的方式遍历
        fmt.Printf(i, ch) //以字节的形式输出,一共13位。UTF-8占据3个字节。byte.使用较多
    }

    for i, ch := range str { //以Unicode方式遍历
        fmt.Printf(i, ch)//以字节的形式输出,一共11位,因为每个字符类型是rune
    }

    [32]byte //define 32 byte array
    [2*N]struct {x,y int32}// 复杂类型数组
    [1000]*float64 //指针数组
    [3][5]int //二维数组
    [2][2][2]float64//等同于[2]([2]([2]float64))

    //Go语言中,数组长度在定义后就不可更改,在声明长度可以为一个常量后者一个常量表达式。常量表达式是指编译期即可计算结果的表达式
    var arr [10]int;
    arrLength := len(arr)
    }

//因为浮点数是不精确的表达,所以无法直接用==来判断两个浮点数是否相等
//采用如下方案
//p 为用户自定义的比较精度,比如0.000001
func IsEqual(f1, f2, p float64) bool {
    b = math.a
    return math.Fdim(f1, f2) < p
}

func GetName() (firstname, lastname, nickname string) {
    return "May", "Chan", "Chibi"
}

数组和数组切片

package main

import "fmt"

func modify(array [5]int) {
    array[0] = 10 //试图修改第一个元素
    fmt.Println("In modify(), array values:", array)
}
func arr() {
    array := [5]int{1, 2, 3, 4, 5}
    modify(array)
    fmt.Println("In main(),array values:", array)

    var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    var mySlice []int = myArray[5:]
    fmt.Println("Elements of Myarray:")
    for _, v := range myArray {
        fmt.Print(v, " ")
    }
    fmt.Println("\n Elements of mySlice:")
    for _, v := range mySlice {
        fmt.Print(v, " ")
    }
    fmt.Println()

    // 可动态增减元素是数组切片比数组更为强大的功能。与数组相比,数组切片多了一个存储能力。即元素个数和分配的空间可以是两个不同的值
    // 合理设置存储能力值,可以大幅度降低数组切片内部重新分配内存和搬送内存块的频率,从而大大提高程序性能

    mySlice1 := make([]int, 5, 6)
    fmt.Println("len(mySlice1)", len(mySlice1))
    fmt.Println("cap(mySlice1)", cap(mySlice1))
    mySlice1 = append(mySlice1, 1, 2)
    mySlice2 := []int{8, 9, 10, 11, 12, 14}
    mySlice2 = append(mySlice1, mySlice2[2:]...) //这里需要添加三个...,映日mySlice1都是int,而mySlice2是[]int类型的,所以需要将元素打散
    fmt.Println(mySlice2)                        //上面会自动扩充mySlice1的大小

    //基于数组切片创建数组切片
    oldSlice := []int{1, 2, 3, 4, 5}
    newSlice := oldSlice[:3] //基于oldslice的前三个元素
    fmt.Println(newSlice)

    slicea := []int{1, 2, 3, 4, 5}
    sliceb := []int{5, 4, 3}
    copy(sliceb, slicea) //智慧复制slicea的前三个元素到sliceb中
    copy(slicea, sliceb) //智慧复制sliceb的3个元素到slicea中
    fmt.Println(slicea)
}

map使用

package main

import "fmt"

type PersonInfo struct {
    ID      string
    Name    string
    Address string
}

func mapf() {
    var personDB map[string]PersonInfo     //变量申明
    personDB = make(map[string]PersonInfo) //变量创建 也可以指定大小 make(map[string] PersonInfo, 100)
    myMap := map[string]PersonInfo{
        "1234": PersonInfo{"1234", "xuan", "Room100"},
    }
    personDB["12345"] = PersonInfo{"12345", "Tome", "Room 123"}
    personDB["1"] = PersonInfo{"1", "Jack", "Room101"}
    //从map中查找键为1234的信息
    person, ok := personDB["1"]
    if ok {
        fmt.Println("Found person", person.Name, "with ID", person.ID)
    } else {
        fmt.Println("Did not find person with ID 1234.")
    }
    delete(myMap, "1234")
}

判断和控制

package main

import "fmt"

func example(x int) int {
    if x == 0 {
        fmt.Println("x==0")
        return x
    } else {
        return 1
    }
}
func main() {
    a := 1
    if a < 5 {
        fmt.Println("a<5")
    } else {
        fmt.Println("a>5")
    }
    b := example(2)
    fmt.Println(b)
    i := 2
    switch i {
    case 0:
        fmt.Printf("0")
    case 1:
        fmt.Printf("1")
    case 2:
        fallthrough //会继续执行下一个case
    case 3, 4, 5, 6:
        fmt.Printf("3,4,5,6")
    default:
        fmt.Printf("Default")
    }
    fmt.Println("\r\nno parameter in switch")
    i = 0
    switch {
    case 0 < i:
        fmt.Println(i)
    case 0 > i:
        fmt.Println("0 > i")
    }

    fmt.Println("for loop")
    sum := 0
    for {
        sum++
        if sum > 100 {
            break
        }
    }
    fmt.Println(sum)

    z := []int{1, 2, 3, 4, 5, 6, 7}
    for i, j := 0, len(z)-1; i < j; i, j = i+1, j-1 {
        z[i], z[j] = z[j], z[i]
    }
    fmt.Println(z)
    for j := 0; j < 5; j++ {
        for i := 0; i < 10; i++ {
            if i > 5 {
                break
            }
            fmt.Println(j, i)
        }
    }
}