Go语言基础

Go语言基础

fetch150zy

新生代 web 开发语言,在网络安全、运维方面也有不错前景

Golang

go 命令

command

  • go bug

    1
    usage: go bug

    打开默认浏览器并且开始bug report,包含有用的系统信息

  • go build

    • 生成的可执行文件默认是文件夹名而不是包名

    用于测试编译,如有必要会编译与之相关联的包

    对于普通包:执行go build之后不会产生任何文件,如果需要生成pkg,使用go install

    对于main包:执行go build之后会产生可执行文件,如果想要在$GOPATH/bin下生成相应可执行文件,使用go install,或者使用go build -o path/binfile

    1
    2
    3
    4
    # go build 默认编译当前目录下所有go文件,如果想要编译单文件
    go build a.go
    # 当然我们也可以指定编译输出的文件名
    go build -o res.out

    go build 会忽略以 . 和 _ 开头的go文件

    1
    2
    3
    $ls
    array_linux.go array_windows.go array_freebsd.go
    # 如果我们在linux下执行go build,会选择性的编译以linux后缀的go文件
  • go clean

    这个命令一般用来清除当前源码包里面编译生成的文件

  • go doc

    展示包的文档

    内置包:go doc bulitin

    http包:go doc net/http

    1
    2
    3
    4
    # 查看某一个包里所有函数
    go doc fmt
    # 查看该函数相应代码
    go doc fmt Printf
  • go env

    打印go的环境信息

  • go fix

    更新包使用新的API

  • go fmt

    格式化代码,不过一般用不到,因为集成开发工具里面自带保存自动格式化

  • go get

    动态获取远程代码包,这个命令内部包含两步:下载源码包,执行go install

  • go list

    列出包或模块

  • go install

    这个命令包含两步:生成可执行文件或者.a包,把编译好的结果移到pkg或bin中

  • go test

    自动读取源码目录下名为*_test.go的文件,生成并运行测试用的可执行文件

go 基础

基础

  • 定义变量

    1
    2
    3
    4
    5
    var var1, var2, var3 type = val1, val2, val3
    // 不指定类型,自动判断
    var var1, var2, var3 = val1, val2, val3
    // 使用 := 简化
    var1 var2 var3 := val1, val2, val3
    1
    2
    // 丢弃第一个值
    _, x := 1, 2

    已声明未使用的变量会在编译期报错

  • 常量

    1
    2
    const constVar = val
    const PI float32 = 3.1415926
  • 内置类型

    • Boolean

      1
      2
      var isTrue bool = false
      isFalse := true
    • int

      1
      2
      3
      4
      5
      6
      7
      8
      9
      int8 uint8 byte
      int16 uint16
      int32 uint32 rune
      int64 uint64

      float32 float64

      // 32 + 32, 64 + 64
      complex64 complex128
    • string

      字符串是不可变的

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      var hello string = "hello"
      emptyStr := ""
      // change string
      // 1.use []byte
      s := "hello"
      c := []byte(s)
      c[0] = 'H'
      s = string(c)
      // 2.use slice
      s := "hello"
      s = "H" + s[1:]
      // + operator
      s1, s2 := "hello", " go"
      s3 := s1 + s2

      // raw string(for multi line string)
      r := `hello
      golang.`
    • error

      1
      2
      3
      4
      err := errors.New("emit macho dwarf: elf header corrupted")
      if err != nil {
      ...
      }
  • 技巧

    • 分组声明

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      import (
      "fmt"
      "os"
      )

      const (
      pi = 3.14
      i = 100
      prefix = "go_"
      )

      var (
      i int
      pi float32
      prefix string
      )
    • iota

      1
      2
      3
      4
      5
      6
      7
      8
      const (
      x = iota // x = 0
      y = iota // y = 1
      z // z = 2
      w // w = 3
      )
      // 每遇到一个关键字,iota重置
      const v = iota // v = 0
    • go设计的一些规则

      • 大写字母开头的变量是可导出的,也就是其它包可以读取的,是公有变量;小写字母开头是不可导出,为私有变量
      • 大写字母开头的函数也一样
  • array slice map

    • array

      1
      2
      3
      4
      var arr [n]type
      arr := [n]type{...}
      // 也可省略长度
      arr := [...]type{...}
      1
      doubleArr := [m][n]type{..., ...}
    • slice

      1
      2
      3
      var slice []type
      slice := []byte{'a', 'b', 'c', 'd'}
      slice = arr[i:j] // i ~ j-1

      内置函数

      1
      2
      3
      4
      5
      6
      7
      8
      //  获取slice的长度
      len(slice)
      // 获取slice的最大容量
      cap(slice)
      // 向slice中添加一个或多个元素,返回相同类型的slice
      slice = append(slice, ...)
      // 复制slice,并返回复制元素个数
      n := copy(destSlice, srcSlice)

      append会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice

      当slice中没有剩余空间时(cap = len),此时将动态分配新的数组空间

      返回的slice数组将指向这个空间,原数组的内容不变

    • map

      1
      2
      var m map[keyType]valType
      m := make(map[keyType]valType)

      map是无序的,只能通过key来获取

      map长度是不固定的,和slice一样是引用类型

      map的初始化是通过key:val的方式初始化,map内置有判断是否存在key的方法

      1
      2
      3
      4
      5
      6
      7
      8
      rating, ok := rate["C"]
      if ok {
      ...
      } else {
      ...
      }
      // 使用delete删除键值对
      delete(rate, "C")

      如果两个map指向同一个底层,那么一个改变另一个也改变

    • make new

      make用于内建类型(map,slice,channel)的内存分配,返回初始化后的值

      new用于各种类型的内存分配,返回指针

  • 零值

    1
    2
    3
    4
    int 0
    uint 0x0
    bool false
    string ""

流程控制和函数

  • 流程控制

    • if

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      if x > 10 {
      ...
      } else {
      ...
      }

      if x := func(); x > 10 {
      ...
      } else if ... {
      ...
      } else {
      ...
      }
    • goto

      1
      2
      3
      Here:
      ...
      goto Here
    • for

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      for i := 0; i < 100; i++ {
      ...
      }
      for sum <= 1000 {
      ...
      }

      outer: for i := 10; i > 0; i-- {
      for j := 1; j < 10; j++ {
      ...
      break outer
      }
      }

      for k, v := range map {
      ...
      }
    • switch

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      switch expr {
      case expr1:
      ...
      case expr2:
      ...
      default:
      ...
      }
      // 匹配成功后自动break,使用fallthrough强制执行后续case代码
      switch i {
      case 1:
      ...
      case 2:
      ...
      fallthrough
      case 3:
      ...
      fallthrough
      default:
      ...
      }
  • 函数

    • 多个返回值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      func returnMultiVal() (int, int, float32) {
      return 1, 2, 3.14
      }
      func returnMultiVal() (a int, b int, pi float32) {
      a = 1
      b = 2
      pi = 3.14
      return
      }
    • 变参

      1
      2
      3
      4
      5
      6
      func myF(args...int) {
      // args is a slice
      for _, n := range args {
      fmt.Println(n)
      }
      }
    • 传值与传指针

      1
      2
      3
      4
      5
      func swap(a *int, b *int) {
      t := *a
      *a = *b
      *b = t
      }

      传指针使得多个函数可以操作同一个对象,传递更轻量化

    • defer

      延迟语句,当函数执行到最后时这些defer语句会逆序执行,最后该函数返回

      1
      2
      3
      4
      5
      6
      7
      8
      9
      func open() bool {
      file.Open("file")
      defer file.Close()
      ...
      if notOK {
      return false
      }
      return true
      }
    • 函数作为值类型

      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
      type int2bool func(int) bool
      func isOdd(i int) bool {
      if i % 2 == 0 {
      return false
      }
      return true
      }

      func isEven(i int) bool {
      if i % 2 == 0 {
      return true
      }
      return false
      }

      func filter(slice []int, f int2bool) []int {
      var res []int
      for _, v := range slice {
      if f(v) {
      res = append(res, v)
      }
      }
      return res
      }

      func main() {
      slice := []int{1, 2, 3, 4, 5, 7}
      odd := filter(slice, isOdd)
      even := filter(slice, isEven)
      }
    • panic和recover

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var user = os.Getenv("USER")

    func init() {
    if user == "" {
    panic("no value for $USER")
    }
    }
    // 检查作为其参数的函数在执行时是否会产生panic
    func throwPanic(f func()) (b bool) {
    defer func() {
    if x := recover(); x != nil {
    b = true
    }
    }()
    f()
    return
    }
    > 应当把panic作为最后的手段来使用 > > > panic是一个内建函数,可以中断原有的控制流程,当在函数中调用panic时,函数的执行被中断,但是函数中的延迟函数正常执行。这一过程会继续向上,直到发生panic的goroutine中所有调用的函数返回。这种错误可以由panic产生,也可以由运行时错误产生。 > > > recover也是内建函数,可以令进入错误的goroutine恢复。recover仅在延迟函数中有效,在正常的执行流程中调用recover会返回nil,没有其它任何效果。
    • main函数和init函数

      一个package中最好只有一个init函数,自动调用init( )和main( ),不需要你显式调用,package中init( )是可选的,但是package main中必须要有main函数

      程序的初始化和执行都起始于main包,如果main包还导入了其它包,那么就会在编译时将他们依次导入。一个包被多个包同时导入,它只会被导入一次。

      当一个包被导入时,如果该包还导入了其它包,那么它会先将其它包导入,然后对这些包中的包级常量和变量进行初始化,接着执行init函数。等所有包都加载完毕,开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数,最后执行main函数

      image-20221218175426562

    • import

      go支持加载自己写的模块

      1
      2
      3
      4
      // 相对路径
      import "./model" // 当前文件同一目录的model目录,但是不建议
      // 绝对路径
      import "shorturl/model" // 加载gopath/src/shorturl/model模块
      • . 操作

        1
        2
        3
        4
        5
        import (
        . "fmt"
        )
        // usage(not need fmt)
        Println(...)
      • 别名操作

        1
        2
        3
        4
        5
        import (
        f "fmt"
        )
        // usage
        f.Println(...)
      • _ 操作

        1
        2
        3
        4
        import (
        _ "github.com/ziutek/mysql/godrv"
        )
        // 只调用里面的init函数

struct

  • struct

    1
    2
    3
    4
    5
    6
    7
    8
    type person struct {
    name string // string字段
    age int8 // int8字段
    }
    var p person
    p.name, p.age = "alex", 18
    p := person{"tom", 20}
    p := person{age:20, name:"mars"}
  • 匿名字段(只提供类型不提供字段名)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    type Human struct {
    name string
    age int8
    weight int8
    }

    type Student struct {
    Human
    stuId string
    }

    mark := Student{Human{"mark", 25, 120}, "200309"}
    // usage
    mark.name
    mark.age
    mark.weight
    mark.stuId

    实现字段的继承,所有内置类型和自定义类型都可以作为匿名字段

oop

  • method

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    type Rect struct {
    width, height float64
    }
    type Circle struct {
    radius float64
    }

    func (r Rect) area() float64 {
    return r.width * r.height
    }
    func (c Circle) area() float64 {
    return c.radius * c.radius * math.Pi
    }

    // usage
    r := Rect{12, 2}
    c := Circle{10}
    r.area()
    c.area()

    exp

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    package main
    import "fmt"
    const(
    WHITE = iota
    BLACK
    BLUE
    RED
    YELLOW
    )
    type Color byte
    type Box struct {
    width, height, depth float64
    color Color
    }
    type BoxList []Box //a slice of boxes
    func (b Box) Volume() float64 {
    return b.width * b.height * b.depth
    }
    func (b *Box) SetColor(c Color) {
    b.color = c
    }
    func (bl BoxList) BiggestsColor() Color {
    v := 0.00
    k := Color(WHITE)
    for _, b := range bl {
    if b.Volume() > v {
    v = b.Volume()
    k = b.color
    }
    }
    return k
    }
    func (bl BoxList) PaintItBlack() {
    for i, _ := range bl {
    bl[i].SetColor(BLACK)
    }
    }
    func (c Color) String() string {
    strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
    return strings[c]
    }
    func main() {
    boxes := BoxList {
    Box{4, 4, 4, RED},
    Box{10, 10, 1, YELLOW},
    Box{1, 1, 20, BLACK},
    Box{10, 10, 1, BLUE},
    Box{10, 30, 1, WHITE},
    Box{20, 20, 20, YELLOW},
    }
    fmt.Printf("We have %d boxes in our set\n", len(boxes))
    fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
    fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String())
    fmt.Println("The biggest one is", boxes.BiggestsColor().String())
    fmt.Println("Let's paint them all black")
    boxes.PaintItBlack()
    fmt.Println("The color of the second one is", boxes[1].color.String())
    fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
    }
    • 指针作为reciver
    • method继承
    • method重写

interface

并发

go web

web工作方式

http包