一、go语言简介

  • 天然支持高并发
  • 内存自动回收,不需要开发人员管理内存
  • 支持管道,从而支持多个协程之间通信
  • 多返回值,一个函数可以允许多个返回值
  • 异常和错误的区分,异常是不能预料到的事情发生了,错误是预料到的事情发生了。

二、理解gopath

  • gopath go项目的工作目录,目录下面包含三个目录,src,pkg,bin
  • goroot go源码的安装路径
  • gobin 存放go编译后生成的可执行文件
  • go get 执行go get会把源码放在第一个gopath的src目录下面

三、go基础知识

3.1 基本数据结构和操作符

    1. 文件名&关键字&标识符(略)
      1. _是特殊标识符,用来忽略结果
    1. Go程序基本结构
      1. 任何一个代码文件隶属于一个包
      1. import 关键字,引用其他包:
      1. golang可执行程序,package main,并且有且只有一个main入口函数
      1. 包中函数调用:a.同一个包中直接实用名称调用;b。不同包中的函数通过包名+点+函数名称进行调用
      1. 包访问控制规则:大写意味函数公有;小写意味函数私有;
    1. 常量和变量
    • 常量使用const 修饰,代表永远是只读的,不能修改。
      1. const 只能修饰boolean,number(int相关类型、浮点类型、complex)和string。
    1. 数据类型和操作符
    • 值类型:变量直接存储值,内存通常在栈中分配。
      • 值类型:基本数据类型int、float、bool、string以及数组和struct。
    • 引用类型:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配。通过GC回收。
      • 引用类型:指针、slice、map、chan等都是引用类型
    • 在函数内部声明的变量叫做局部变量,生命周期仅限于函数内部。
    • 在函数外部声明的变量叫做全局变量,生命周期作用于整个包,如果是大写的,则作用于整个程序。
    • bool类型,只能存true和false
    • 相关操作符, !、&&、||
    • 数字类型,主要有int、int8、int16、int32、int64、uint8、uint16、uint32、uint64、float32、float64
    • 类型转换,type(variable),比如:var a int=8; var b int32=int32(a)
    • 逻辑操作符:== 、!=、<、<=、>和 >=
    • 数学操作符:+、-、*、/等等
    1. 字符串类型
    • 字符类型:var a byte
    • 字符串类型: var str string
    • 字符串表示两种方式: 1)双引号2)``(不需要转义)

3.2 字符串处理&时间和日期类型&指针类型&流程控制&函数详解

  1. strings和strconv使用
    • strings.HasPrefix(s string, prefix string) bool:判断字符串s是否以prefix开头。
      1. strings.HasSuffix(s string, suffix string) bool:判断字符串s是否以suffix结尾。
      1. strings.Index(s string, str string) int:判断str在s中首次出现的位置,如果没有出现,则返回-1
      1. strings.LastIndex(s string, str string) int:判断str在s中最后出现的位置,如果没有出现,则返回-1
      1. strings.Replace(str string, old string, new string, n int):字符串替换
      1. strings.Count(str string, substr string)int:字符串计数
      1. strings.Repeat(str string, count int)string:重复count次str
      1. strings.ToLower(str string)string:转为小写
      1. strings.ToUpper(str string)string:转为大写
    • strings.TrimSpace(str string):去掉字符串首尾空白字符
    • strings.Trim(str string, cut string):去掉字符串首尾cut字符
    • strings.TrimLeft(str string, cut string):去掉字符串首cut字符
    • strings.TrimRight(str string, cut string):去掉字符串首cut字符
    • strings.Field(str string):返回str空格分隔的所有子串的slice
    • strings.Split(str string, split string):返回str split分隔的所有子串的slice
    • strings.Join(s1 []string, sep string):用sep把s1中的所有元素链接起来
    • strings.Itoa(i int):把一个整数i转成字符串
    • strings.Atoi(str string)(int, error):把一个字符串转成整数
  2. Go中的时间和日期类型
      1. time包
      1. time.Time类型,用来表示时间
      1. 获取当前时间, now := time.Now()
      1. time.Now().Day(),time.Now().Minute(),time.Now().Month(),time.Now().Year()
      1. 格式化,fmt.Printf("%02d/%02d%02d %02d:%02d:%02d", now.Year()…)
      1. time.Duration用来表示纳秒
  3. 指针类型
      1. 普通类型,变量存的就是值,也叫值类型
      1. 获取变量的地址,用&,比如: var a int, 获取a的地址:&a
      1. 指针类型,变量存的是一个地址,这个地址存的才是值
      1. 获取指针类型所指向的值,使用:*,比如:var p int, 使用p获取p指向的值
  4. 流程控制
      1. If / else分支判断
      1. switch case语句,可以使用fallthrough强制执行后面的case代码
      1. for 语句
      1. for range 语句
      1. break continue语句
      1. goto 和 label 语句 (明天补充)
  5. 函数详解
      1. 声明语法:func 函数名 (参数列表) [(返回值列表)] {}
      1. golang函数特点:
      • a. 不支持重载,一个包不能有两个名字一样的函数
      • b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
      • c. 匿名函数
      • d. 多返回值
      1. 函数参数传递方式:
      • 1). 值传递
      • 2). 引用传递 注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。 注意2:map、slice、chan、指针、interface默认以引用的方式传递
      1. _标识符,用来忽略返回值:
      1. 可变参数:func add(a int, b int, arg…int) int {} //两个或多个参数
    • 注意:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数
      1. defer用途:
        1. 当函数返回时,执行defer语句。因此,可以用来做资源清理
        1. 多个defer语句,按先进后出的方式执行
        1. defer语句中的变量,在defer声明时就决定了。
        1. defer的用途:关闭文件句柄;释放资源;关闭数据库连接

3.3 内置函数、递归函数、闭包

内置函数
    1. close:主要用来关闭channel
    1. len:用来求长度,比如string、array、slice、map、channel
    1. new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
    1. make:用来分配内存,主要用来分配引用类型,比如chan、map、slice
    1. append:用来追加元素到数组、slice中
    1. panic和recover:用来做不可预料的异常捕获
    1. new和make的区别
    • New与make都是用来分配内存。不同点:new用来分配值类型,make用来分配引用类型;new返回的是一个指针,make返回的是值类型。
递归函数
    1. 一个函数调用自己,就叫做递归。
    1. 斐波那契数
    1. 递归的设计原则
    • 1)一个大的问题能够分解成相似的小问题
    • 2)定义好出口条件
闭包
  • 一个函数和与其相关的引用环境而组合成的实体。

3.4 数组和切片、map数据结构

数组
  1. 数组:是同一种数据类型的固定长度的序列。
  2. 数组定义:var a [len]int,比如:var a[5]int
  3. 长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型
  4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
  5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
  6. 数组是值类型,因此改变副本的值,不会改变本身的值
  7. 数组初始化
切片
  1. 切片:切片是数组的一个引用,因此切片是引用类型
  2. 切片的长度可以改变,因此,切片是一个可变的数组
  3. 切片遍历方式和数组一样,可以用len()求长度
  4. cap可以求出slice最大的容量,0 <= len(slice) <= (array),其中array是slice引用的数组
  5. 切片的定义:var 变量名 []类型,比如 var str []string var arr []int
Slice的数据结构
Type slice struct {
	ptr *[5]type
	len int
	cap int
}
Cap:不指定的话,默认为2^0 2^1 2^2 2^n n为元素的个数

  1. 通过make来创建切片(另一种通过数组创建切片)
    • var slice []type = make([]type, len)
    • slice := make([]type, len)
    • slice := make([]type, len, cap)
  2. 用append内置函数操作切片,当切片容量不够,会自动扩容,创建一个新的地址。
  3. For range 遍历切片
  4. 切片拷贝
  5. string与slice
    • string底层就是一个byte的数组,因此,也可以进行切片操作
Type string struct {
	ptr *[5]byte
	len int
}
- 想要改变string中的字符值,首先需要把字符串转换成byte切片
  1. 排序和查找操作
    • sort.Ints对整数进行排序, sort.Strings对字符串进行排序, sort.Float64s对浮点数排序
    • sort.SearchInts(a []int, b int) 从数组a中查找b,前提是a必须有序
    • sort.SearchFloats(a []float64, b float64) 从数组a中查找b,前提是a必须有序
    • sort.SearchStrings(a []string, b string) 从数组a中查找b,前提是a必须有序
map数据结构
  1. key-value的数据结构,又叫字典或关联数组
    • 声明 var a map[string]string
    • 声明是不会分配内存的,初始化需要make
  2. map相关操作
    • var a = map[string]string{"key":"value"}
    • a = make(map[string]string, 10)
    • a[“hello”] = “world” //插入或者更新
    • Val, ok := a[“hello”] // 查找
    • for k, v := range a //遍历
    • delete(a, “hello”) //删除
  3. map是引用类型
  4. slice of map
    • 字典类型的数组
    • Map类型的slice初始化
Items := make([]map[int][int], 5)
For I := 0; I < 5; i++ {
        items[i] = make(map[int][int])
}
  1. map排序
    • a. 先获取所有key,把key进行排序
    • b. 按照排序好的key,进行遍历
  2. Map反转
    • a. 初始化另外一个map,把key、value互换即可

3.5 package介绍

  1. golang中的包
    • a. golang目前有150个标准的包,覆盖了几乎所有的基础库
    • b. golang.org有所有包的文档,没事都翻翻
  2. 线程同步
    • a. import(“sync”)
    • b. 互斥锁, var mu sync.Mutex
    • c. 读写锁, var mu sync.RWMutex
    • d. 为什么要有锁:十字路口是公有的资源,红绿灯就是锁。为了避免小车争抢资源就要上锁。
  3. 课后作业 实现一个冒泡排序、选择排序、插入排序、快速排序(参考书籍及搜索引擎)

3.6 结构体&方法&接口

结构体的特点
  1. 用来自定义复杂数据结构
  2. struct里面可以包含多个字段(属性)
  3. struct类型可以定义方法,注意和函数的区分
  4. struct类型是值类型
  5. struct类型可以嵌套
  6. Go语言没有class类型,只有struct类型
结构体的定义以及初始化
  1. struct 声明:
  2. struct 中字段访问:和其他语言一样,使用点
  3. struct定义的三种形式:
    1. var stu Student
    2. var stu *Student = new (Student)
    3. var stu *Student = &Student{}
    • 其中2和3返回的都是指向结构体的指针,访问形式:a. stu.Name、stu.Age和stu.Score或者 (*stu).Name、(*stu).Age等
  4. struct的内存布局:struct中的所有字段在内存是连续的,布局如下:
  5. 链表定义
    • 每个节点包含下一个节点的地址,这样把所有的节点串起来了,通常把 链表中的第一个节点叫做链表头
type Student struct {
       Name string
       Next* Student
}
  1. 双链表定义
    • 如果有两个指针分别指向前一个节点和后一个节点,我们叫做双链表
type Student struct {
       Name string
       Next* Student
       Prev* Student
}
  1. 二叉树定义
    • 如果每个节点有两个指针分别用来指向左子树和右子树,我们把这样的结构叫做二叉树
type Student struct {
       Name string
       left* Student
       right* Student
}

  1. 结构体是用户单独定义的类型,不能和其他类型进行强制转换
  2. golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题
type student struct {
	Name string
	Age 	int
}

func NewStudent(name string, age int) *student {
	return &student{
		Name:name,
		Age:age,
	}
}
func main()  {
	s := new(student)
	a := NewStudent("tony", 23)
	s = a
	fmt.Println(*s)
	fmt.Println(*a)

}
  1. 再次强调:
    • make 用来创建map、slice、channel、interface,new用来创建值类型
  2. 我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化
type student struct {
    Name stirng  "this is name field"
    Age int      "this is age field"
}

  1. 结构体中字段可以没有名字,即匿名字段
type Train struct {
        Car
        Start time.Time
        int
}

3.7 方法

  1. Golang中的方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct
    • 定义:func (recevier type) methodName(参数列表)(返回值列表){}
  2. 方法的调用
type A struct {
    a int
}

func (this A) test() {
    fmt.Println(this.a)
}

var t A
t.test()

  1. 方法和函数的区别
    • 函数调用: function(variable, 参数列表)
    • 方法调用:variable.function(参数列表)
  2. 指针receiver vs 值receiver
    • 本质上和函数的值传递和地址传递是一样的
  3. 方法的访问控制,通过大小写控制
  4. 继承
    • 如果一个struct嵌套了另一个匿名结构体,那么这个结构可以直接访问匿名结构体的方法,从而实现了继承。
  5. 组合和匿名字段
    • 如果一个struct嵌套了另一个有名结构体,那么这个模式就叫组合
  6. 多重继承
    • 如果一个struct嵌套了多个匿名结构体,那么这个结构可以直接访问多个匿名结构体的方法,从而实现了多重继承。
  7. 实现String()
    • 如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出。

3.8 接口

接口的定义
  1. interface类型可以定义一组方法,但是这些方法不需要实现。并且interface不能包含任何变量。
  2. 定义接口
type example interface {
    Method1(parse1) return1
    method2(parse1) return1
}
  1. interface类型默认是一个指针
  2. 接口实现
    • a. Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字
    • b. 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
    • c. 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。
  3. 多态 一种事物的多种形态,都可以按照统一的接口进行操作
  4. 接口嵌套 一个接口可以嵌套在另外的接口
package main

type ReadWrite interface {
	Read()
	Write()
	
}

type Lock interface {
	Lock()
	Unlock()
}

type File interface {
	ReadWrite
	Lock
	Close()
}

8.类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,可以采用以下方法进行转换:

var t int 
var x interface{}
x = t
y, ok := x.(int) //转成int
if ok {...}
switch b := x.(type) {
	case int:
		fmt.Println("int:", b)
	case string:
		fmt.Println("string", b)
	default:
		fmt.Println("i don't know")
	}
  1. 空接口 interface{},空接口没有任何方案,所有类型都实现了空接口,可以使用空接口
var a int
var b interface{}
b  = a

  1. 判断一个变量是否实现了指定接口

    • if sv, ok := v.(Stringer); ok {}
  2. 问题

      1. 指针类型和值类型的区别
      1. 实现一个通用的链表类
      1. 实现一个负载均衡调度算法,支持随机、轮训等算法
      1. 变量slice和接口slice之间赋值操作,for range???

3.9 反射

  1. 反射:可以在运行时动态获取变量的相关信息Import (“reflect”)
    • a. reflect.TypeOf,获取变量的类型,返回reflect.Type类型
    • b. reflect.ValueOf,获取变量的值,返回reflect.Value类型
    • c. reflect.Value.Kind,获取变量的类别,返回一个常量
    • d. reflect.Value.Interface(),转换成interface{}类型
    • 变量 <--> interface <--> Reflect.Value
  2. 获取变量的值
    • reflect.ValueOf(x).Float()
    • reflect.ValueOf(x).Int()
    • reflect.ValueOf(x).String()
    • reflect.ValueOf(x).Bool()
  3. 通过反射的来改变变量的值
    • reflect.Value.SetXX相关方法,比如:
    • reflect.Value.SetFloat(),设置浮点数
    • reflect.Value.SetInt(),设置整数
    • reflect.Value.SetString(),设置字符串
package main

import (
	"fmt"
	"reflect"
)

func main() {

	var a float64
	fv := reflect.ValueOf(&a)
	fv.Elem().SetFloat(3.3)
	fmt.Printf("%v\n", a)
}
fv.Elem()用来获取指针指向的变量
  1. 用反射操作结构体 ???
    • a. reflect.Value.NumField()获取结构体中字段的个数
    • b. reflect.Value.Method(n).Call来调用结构体中的方法

3.9 终端以及文件操作

  1. 终端读写
    • os.Stdin:标准输入
    • os.Stdout:标准输出
    • os.Stderr:标准错误输出
  2. 带缓冲区的读写:
    • var inputReader *bufio.Reader //声明一个结构体类型的变量
    • inputReader = bufio.NewReader(os.Stdin) //读取标准输入
    • input, err = inputReader.ReadString('\n') // 读取换行
  3. os.File封装所有文件相关操作,之前讲的 os.Stdin,os.Stdout, os.Stderr都是*os.File
    • 打开一个文件进行读操作: os.Open(name string) (*File, error)
    • 关闭一个文件:File.Close()
    • bufio.NewReader //构造一个reader结构体
    • inputReader.ReadString //逐行读取
    • ioutil.ReadFile(inputFile) //读取整个文件
    • ioutil.WriteFile(outputFile,buf,0x644) //写入整个文件
    • gzip.NewReader(fi) //构造一个压缩文件的reader结构体
  4. 文件写入
    • os.OpenFile(“output.dat”, os.O_WRONLY|os.O_CREATE, 0666)
    • 第二个参数:文件打开模式:
    • 第三个参数:权限控制:
    • bufio.NewWriter(outputFile) //构建一个写入文件的writer
    • outputWriter.WriteString(outputString) //写入文件
    • outputWriter.Flush() 提交
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main()  {
	inputFile, err := os.Open("file")
	if err != nil {
		fmt.Printf("open file err:%v\n", err)
		return
	}

	defer inputFile.Close()

	inputReader := bufio.NewReader(inputFile)
	for {
		inputString, readerError := inputReader.ReadString('\n')
		if readerError == io.EOF {
			return
		}
		fmt.Printf("the input was %s", inputString)
	}

}
//读取以及写入整个文件
package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main()  {
	inputFile := "file"
	outputFile := "output_file"
	buf, err := ioutil.ReadFile(inputFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "File Error:%s\n", err)
		return
	}
	fmt.Printf("%s\n",string(buf))
	err = ioutil.WriteFile(outputFile,buf,0x644)
	if err != nil {
		panic(err.Error())
	}

}
//读取压缩文件
gzip.NewReader(fi)
//写入文件
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main()  {
	outputFile, outputErr := os.OpenFile("new_file", os.O_WRONLY|os.O_CREATE,0666)
	if outputErr != nil {
		fmt.Printf("An error occurred with file creation\n")
		return
	}
	defer outputFile.Close()
	outputWriter := bufio.NewWriter(outputFile)
	outputString := "hello world!\n"
	for i:= 0;i < 10; i++ {
		outputWriter.WriteString(outputString)
	}
	outputWriter.Flush()
}

  1. 拷贝文件 io.Copy(dst, src)
  2. os.Args是一个string的切片,用来存储所有的命令行参数
  3. flag包的使用,用来解析命令行参数:
	flag.BoolVar(&test, "b", false, "print on newline")
	flag.StringVar(&str, "s", "", "print on newline")
	flag.IntVar(&count, "c", 1001, "print on newline")

package main

import (
	"flag"
	"fmt"
)

func main()  {
	var test bool
	var str string
	var count int

	flag.BoolVar(&test, "b", false, "print on newline")
	flag.StringVar(&str, "s", "hello", "print on newline")
	flag.IntVar(&count, "c", 1001, "print on newline")
	flag.Parse()

	fmt.Println(test,str,count)
}
package main

import (
	"bufio"
	"fmt"
	"os"
)

//带缓冲的区的终端读写
func main()  {
	fmt.Fprintf(os.Stdout,"%s\n","hello world!-unbuffered")
	buf := bufio.NewWriter(os.Stdout)
	fmt.Fprintf(buf, "%s\n", "hello world!-buffered" )
	buf.Flush()
}

四、中阶知识

4.1 json数据协议

  1. golang --> json字符串 --> 网络传输 --> 程序 --> 其他语言
    1. 导入包:Import “encoding/json”
    2. 序列化: json.Marshal(data interface{}) //json化
    3. 反序列化: json.UnMarshal(data []byte, v interface{}) //解析json
  2. json序列化结构体
  3. json序列化map

4.2 错误处理

  1. 定义错误 var errNotFound error = errors.New("Not found error")
  2. 自定义错误
  3. 如何判断自定义错误
  4. pannic 这一部分参考俯瞰四维

五、并发编程

六、高阶编程

6.1 tcp编程

6.2 redis

redis是个开源的高性能的key-value的内存数据库,可以把它当成远程的数据结构。支持的value类型非常多,比如string、list(链表)、set(集合)、hash表等等。redis性能非常高,单机能够达到15w qps,通常适合做缓存。使用第三方开源的redis库: github.com/garyburd/redigo/redis

  • 链接redis c, err := redis.Dial("tcp", "localhost:6379")
  • Set 接口 _, err = c.Do("Set", "abc", 100) r, err := redis.Int(c.Do("Get", "abc"))
  • Hash表 _, err = c.Do("HSet", "books", "abc", 100) r, err := redis.Int(c.Do("HGet", "books", "abc"))
  • . 批量Set _, err = c.Do("MSet", "abc", 100, "efg", 300) r, err := redis.Ints(c.Do("MGet", "abc", "efg"))
  • 过期时间 _, err = c.Do("expire", "abc", 10)
  • 队列操作 _, err = c.Do("lpush", "book_list", "abc", "ceg", 300) r, err := redis.String(c.Do("lpop", "book_list"))

6.3 http编程

特点
  • a. Go原生支持http,import(“net/http”)
  • b. Go的http服务性能和nginx比较接近
  • c. 几行代码就可以实现一个web服务
  1. 处理http请求 使用 net/http 包提供的 http.ListenAndServe() 方法,可以在指定的地址进行监听, 开启一个HTTP,服务端该方法的原型:func ListenAndServe(addr string, handler Handler) error <br> 第二个参数表示服务端处理程序, 通常为空,这意味着服务端调用 http.DefaultServeMux 进行处理,而服务端编写的业务逻 辑处理程序 http.Handle() 或 http.HandleFunc() 默认注入 http.DefaultServeMux 中
  2. 处理https请求 func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error
  3. 路由 http.HandleFunc()方法接受两个参数
    • 第一个参数是HTTP请求的 目标路径"/hello",该参数值可以是字符串,也可以是字符串形式的正则表达式
    • 第二个参数指定具体的回调方法,比如helloHandler
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(“hello beifeng!”))
	})

  1. post访问
resp, err:=http.Get(“.....”)

defer resp.Body.Close()

body,err:=ioutil.ReadAll(resp.Body)

fmt.Println(string(body))

  1. post访问
resp, err:=http.Post(“.....”, ”application/x-www-form-urlencoded”, strings.NewReader(“..=...”))

defer resp.Body.Close()

body,err:=ioutil.ReadAll(resp.Body)

fmt.Println(string(body))

6.4 正则表达式

Go语言标准库内建提供了regexp包

. 	匹配除换行符以外的任意字符
\w 	匹配字母或数字或下划线或汉字
\s 	匹配任意的空白符
\d 	匹配数字
\b 	匹配单词的开始或结束
^ 	匹配字符串的开始
$ 	匹配字符串的结束

* 	重复零次或更多次
+ 	重复一次或更多次
? 	重复零次或一次
{n} 	重复n次
{n,} 	重复n次或更多次
{n,m} 	重复n到m次

捕获 (exp) 	匹配exp,并捕获文本到自动命名的组里

(?<name>exp) 	匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)

(?:exp) 		匹配exp,不捕获匹配的文本,也不给此分组分配组号

func Match(pattern string, b []byte) (matched bool, err error)
func MatchString(pattern string, s string) (matched bool, err error)
func MustCompile(str string) *Regexp
func (re *Regexp) FindAllString(s string, n int) []string
https://my.oschina.net/kuerant/blog/199146

6.5 mysql编程

  1. mysql驱动 https://github.com/Go-SQL-Driver/MySQL

  2. sqlx

  • database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
  • r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com")
  • err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)
  • _, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1)
  • _, err := Db.Exec("delete from person where user_id=?", 1)

6.6 beego框架

beego.me

beego框架之请求数据处理

  • ``符号,表示里面的不用转义
  • 直接解析到struct
    • c.ParseForm(&u)
  • 获取request body里的内容
      1. 在配置文件里设置 copyrequestbody = true
      1. this.Ctx.Input.RequestBody