go语言基础知识汇总
文件名&关键字&标识符(略)_是特殊标识符,用来忽略结果Go程序基本结构任何一个代码文件隶属于一个包import 关键字,引用其他包:golang可执行程序,package main,并且有且只有一个main入口函数包中函数调用:a.同一个包中直接实用名称调用;b。不同包中的函数通过包名+点+函数名称进行调用包访问控制规则:大写意味函数公有;小写意味函数私有;常量和变量常量使用const 修饰,代表永远是只读的,不能修改。const 只能修饰boolean,number(int相关类型、浮点类型、complex)和string。数据类型和操作符值类型:变量直接存储值,内存通常在栈中分配。值类型:基本数据类型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)逻辑操作符:== 、!=、<、<=、>和 >=数学操作符:+、-、*、/等等字符串类型字符类型:var a byte字符串类型: var str string字符串表示两种方式: 1)双引号2)``(不需要转义)3.2 字符串处理&时间和日期类型&指针类型&流程控制&函数详解strings和strconv使用strings.HasPrefix(s string, prefix string) bool:判断字符串s是否以prefix开头。strings.HasSuffix(s string, suffix string) bool:判断字符串s是否以suffix结尾。strings.Index(s string, str string) int:判断str在s中首次出现的位置,如果没有出现,则返回-1strings.LastIndex(s string, str string) int:判断str在s中最后出现的位置,如果没有出现,则返回-1strings.Replace(str string, old string, new string, n int):字符串替换strings.Count(str string, substr string)int:字符串计数strings.Repeat(str string, count int)string:重复count次strstrings.ToLower(str string)string:转为小写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空格分隔的所有子串的slicestrings.Split(str string, split string):返回str split分隔的所有子串的slicestrings.Join(s1 []string, sep string):用sep把s1中的所有元素链接起来strings.Itoa(i int):把一个整数i转成字符串strings.Atoi(str string)(int, error):把一个字符串转成整数Go中的时间和日期类型time包time.Time类型,用来表示时间获取当前时间, now := time.Now()time.Now().Day(),time.Now().Minute(),time.Now().Month(),time.Now().Year()格式化,fmt.Printf("%02d/%02d%02d %02d:%02d:%02d", now.Year()…)time.Duration用来表示纳秒指针类型普通类型,变量存的就是值,也叫值类型获取变量的地址,用&,比如: var a int, 获取a的地址:&a指针类型,变量存的是一个地址,这个地址存的才是值获取指针类型所指向的值,使用:,比如:var p int, 使用*p获取p指向的值流程控制If / else分支判断switch case语句,可以使用fallthrough强制执行后面的case代码for 语句for range 语句break continue语句goto 和 label 语句 (明天补充)函数详解声明语法:func 函数名 (参数列表) [(返回值列表)] {}golang函数特点:a. 不支持重载,一个包不能有两个名字一样的函数b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量c. 匿名函数d. 多返回值函数参数传递方式:1). 值传递2). 引用传递
注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
注意2:map、slice、chan、指针、interface默认以引用的方式传递_标识符,用来忽略返回值:可变参数:func add(a int, b int, arg…int) int {} //两个或多个参数注意:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数defer用途:当函数返回时,执行defer语句。因此,可以用来做资源清理多个defer语句,按先进后出的方式执行defer语句中的变量,在defer声明时就决定了。defer的用途:关闭文件句柄;释放资源;关闭数据库连接3.3 内置函数、递归函数、闭包
内置函数
close:主要用来关闭channellen:用来求长度,比如string、array、slice、map、channelnew:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针make:用来分配内存,主要用来分配引用类型,比如chan、map、sliceappend:用来追加元素到数组、slice中panic和recover:用来做不可预料的异常捕获new和make的区别New与make都是用来分配内存。不同点:new用来分配值类型,make用来分配引用类型;new返回的是一个指针,make返回的是值类型。递归函数
一个函数调用自己,就叫做递归。斐波那契数递归的设计原则1)一个大的问题能够分解成相似的小问题2)定义好出口条件闭包
一个函数和与其相关的引用环境而组合成的实体。3.4 数组和切片、map数据结构数组
数组:是同一种数据类型的固定长度的序列。数组定义:var a [len]int,比如:var a[5]int长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic数组是值类型,因此改变副本的值,不会改变本身的值数组初始化切片
切片:切片是数组的一个引用,因此切片是引用类型切片的长度可以改变,因此,切片是一个可变的数组切片遍历方式和数组一样,可以用len()求长度cap可以求出slice最大的容量,0 <= len(slice) <= (array),其中array是slice引用的数组切片的定义: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为元素的个数
通过make来创建切片(另一种通过数组创建切片)var slice []type = make([]type, len)slice := make([]type, len)slice := make([]type, len, cap)用append内置函数操作切片,当切片容量不够,会自动扩容,创建一个新的地址。For range 遍历切片切片拷贝string与slicestring底层就是一个byte的数组,因此,也可以进行切片操作
Type string struct {ptr *[5]bytelen int}
想要改变string中的字符值,首先需要把字符串转换成byte切片排序和查找操作 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数据结构
key-value的数据结构,又叫字典或关联数组声明 var a map[string]string声明是不会分配内存的,初始化需要makemap相关操作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”) //删除map是引用类型slice of map字典类型的数组Map类型的slice初始化
Items := make([]map[int][int], 5)For I := 0; I < 5; i++ {items[i] = make(map[int][int])}
map排序a. 先获取所有key,把key进行排序b. 按照排序好的key,进行遍历Map反转a. 初始化另外一个map,把key、value互换即可3.5 package介绍
golang中的包a. golang目前有150个标准的包,覆盖了几乎所有的基础库b. golang.org有所有包的文档,没事都翻翻线程同步a. import(“sync”)b. 互斥锁, var mu sync.Mutexc. 读写锁, var mu sync.RWMutexd. 为什么要有锁:十字路口是公有的资源,红绿灯就是锁。为了避免小车争抢资源就要上锁。课后作业
实现一个冒泡排序、选择排序、插入排序、快速排序(参考书籍及搜索引擎)3.6 结构体&方法&接口结构体的特点
用来自定义复杂数据结构struct里面可以包含多个字段(属性)struct类型可以定义方法,注意和函数的区分struct类型是值类型struct类型可以嵌套Go语言没有class类型,只有struct类型结构体的定义以及初始化struct 声明:struct 中字段访问:和其他语言一样,使用点struct定义的三种形式:var stu Studentvar stu *Student = new (Student)var stu *Student = &Student{}其中2和3返回的都是指向结构体的指针,访问形式:a. stu.Name、stu.Age和stu.Score或者 (stu).Name、(stu).Age等struct的内存布局:struct中的所有字段在内存是连续的,布局如下:链表定义每个节点包含下一个节点的地址,这样把所有的节点串起来了,通常把
链表中的第一个节点叫做链表头
type Student struct {Name stringNext* Student}
双链表定义如果有两个指针分别指向前一个节点和后一个节点,我们叫做双链表
type Student struct {Name stringNext* StudentPrev* Student}
二叉树定义如果每个节点有两个指针分别用来指向左子树和右子树,我们把这样的结构叫做二叉树
type Student struct { Name string left* Student right* Student}
结构体是用户单独定义的类型,不能和其他类型进行强制转换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)}
再次强调:make 用来创建map、slice、channel、interface,new用来创建值类型我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化
type student struct { Name stirng "this is name field" Age int "this is age field"}
结构体中字段可以没有名字,即匿名字段
type Train struct { Car Start time.Time int}
3.7 方法
Golang中的方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct定义:func (recevier type) methodName(参数列表)(返回值列表){}方法的调用
type A struct { a int}func (this A) test() { fmt.Println(this.a)}var t At.test()
方法和函数的区别函数调用: function(variable, 参数列表)方法调用:variable.function(参数列表)指针receiver vs 值receiver本质上和函数的值传递和地址传递是一样的 方法的访问控制,通过大小写控制继承如果一个struct嵌套了另一个匿名结构体,那么这个结构可以直接访问匿名结构体的方法,从而实现了继承。组合和匿名字段如果一个struct嵌套了另一个有名结构体,那么这个模式就叫组合。多重继承如果一个struct嵌套了多个匿名结构体,那么这个结构可以直接访问多个匿名结构体的方法,从而实现了多重继承。实现String()如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出。3.8 接口接口的定义
interface类型可以定义一组方法,但是这些方法不需要实现。并且interface不能包含任何变量。 定义接口
type example interface {Method1(parse1) return1method2(parse1) return1}
interface类型默认是一个指针接口实现a. Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字b. 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。c. 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。多态
一种事物的多种形态,都可以按照统一的接口进行操作接口嵌套
一个接口可以嵌套在另外的接口
package maintype ReadWrite interface { Read() Write()}type Lock interface { Lock() Unlock()}type File interface { ReadWrite Lock Close()}
8.类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,可以采用以下方法进行转换:
var t int var x interface{}x = ty, ok := x.(int) //转成intif ok {...}switch b := x.(type) { case int: fmt.Println("int:", b) case string: fmt.Println("string", b) default: fmt.Println("i don't know") }
空接口 interface{},空接口没有任何方案,所有类型都实现了空接口,可以使用空接口
var a intvar b interface{}b = a
判断一个变量是否实现了指定接口
if sv, ok := v.(Stringer); ok {}问题指针类型和值类型的区别实现一个通用的链表类实现一个负载均衡调度算法,支持随机、轮训等算法变量slice和接口slice之间赋值操作,for range???3.9 反射反射:可以在运行时动态获取变量的相关信息Import (“reflect”)a. reflect.TypeOf,获取变量的类型,返回reflect.Type类型b. reflect.ValueOf,获取变量的值,返回reflect.Value类型c. reflect.Value.Kind,获取变量的类别,返回一个常量d. reflect.Value.Interface(),转换成interface{}类型变量 <--> interface <--> Reflect.Value获取变量的值reflect.ValueOf(x).Float() reflect.ValueOf(x).Int()reflect.ValueOf(x).String()reflect.ValueOf(x).Bool()通过反射的来改变变量的值reflect.Value.SetXX相关方法,比如:reflect.Value.SetFloat(),设置浮点数reflect.Value.SetInt(),设置整数reflect.Value.SetString(),设置字符串
package mainimport ( "fmt" "reflect")func main() { var a float64 fv := reflect.ValueOf(&a) fv.Elem().SetFloat(3.3) fmt.Printf("%v\n", a)}fv.Elem()用来获取指针指向的变量
用反射操作结构体 ???a. reflect.Value.NumField()获取结构体中字段的个数b. reflect.Value.Method(n).Call来调用结构体中的方法3.9 终端以及文件操作终端读写os.Stdin:标准输入 os.Stdout:标准输出os.Stderr:标准错误输出带缓冲区的读写:var inputReader *bufio.Reader //声明一个结构体类型的变量inputReader = bufio.NewReader(os.Stdin) //读取标准输入input, err = inputReader.ReadString('\n') // 读取换行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结构体文件写入os.OpenFile(“output.dat”, os.O_WRONLY|os.O_CREATE, 0666)第二个参数:文件打开模式:第三个参数:权限控制:bufio.NewWriter(outputFile) //构建一个写入文件的writeroutputWriter.WriteString(outputString) //写入文件outputWriter.Flush() 提交
package mainimport ( "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 mainimport ( "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 mainimport ( "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()}
拷贝文件 io.Copy(dst, src) os.Args是一个string的切片,用来存储所有的命令行参数 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 mainimport ( "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 mainimport ( "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数据协议golang --> json字符串 --> 网络传输 --> 程序 --> 其他语言导入包:Import “encoding/json”序列化: json.Marshal(data interface{}) //json化反序列化: json.UnMarshal(data []byte, v interface{}) //解析jsonjson序列化结构体json序列化map4.2 错误处理定义错误 var errNotFound error = errors.New("Not found error")自定义错误如何判断自定义错误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服务处理http请求
使用 net/http 包提供的 http.ListenAndServe() 方法,可以在指定的地址进行监听, 开启一个HTTP,服务端该方法的原型:func ListenAndServe(addr string, handler Handler) error <br>
第二个参数表示服务端处理程序, 通常为空,这意味着服务端调用 http.DefaultServeMux 进行处理,而服务端编写的业务逻 辑处理程序 http.Handle() 或 http.HandleFunc() 默认注入 http.DefaultServeMux 中处理https请求 func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error 路由 http.HandleFunc()方法接受两个参数第一个参数是HTTP请求的 目标路径"/hello",该参数值可以是字符串,也可以是字符串形式的正则表达式第二个参数指定具体的回调方法,比如helloHandler
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(“hello beifeng!”)) })
post访问
resp, err:=http.Get(“.....”)defer resp.Body.Close()body,err:=ioutil.ReadAll(resp.Body)fmt.Println(string(body))
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) *Regexpfunc (re *Regexp) FindAllString(s string, n int) []stringhttps://my.oschina.net/kuerant/blog/199146
6.5 mysql编程
mysql驱动
https://github.com/Go-SQL-Driver/MySQL
beego.me
beego框架之请求数据处理``符号,表示里面的不用转义直接解析到structc.ParseForm(&u)获取request body里的内容在配置文件里设置 copyrequestbody = truethis.Ctx.Input.RequestBody声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。