Go学习(二十):Web开发-HTTP服务端启动的几种方式
1. 怎么启动Web服务?Go语言标准库内置的net/http包,可以实现HTTP服务端。实现HTTP服务端就是能够启动Web服务,相当于搭建起了一个Web服务器。http.ListenAndServer()函数用来启动Web服务,绑定并监听http端口。
123func ListenAndServe(addr string, handler Handler)// addr:监听地址;如 :8080 或者0.0.0.0:8080// handler:HTTP处理器Handler
2.启动Web服务的几种方式根据不同服务返回的handler,常见启动Web服务有以下几种方式。
2.1 http.FileServer: 静态文件服务http.FileServer()搭建的服务器只提供静态文件的访问。因为这种web服务只支持静态文件访问,所以称之为静态文件服务。
1.使用示例文件目录如下:
123456789101112package mainimport ( "net/http")func main() { runFileServer()}/ ...
Go学习(十九):并发编程-sync包
1.介绍sync包提供了互斥锁。除了Once和WaitGroup类型,其余多数适用于低水平的程序,多数情况下,高水平的同步使用channel通信性能会更优一些。
2.并发等待组(WaitGroup)WaitGroup,即等待一组Goroutine结束。父Goroutine调用Add()方法来设置应等待Goroutine的数量。每个被等待的Goroutine在结束时应该调用Done()方法。与此同时,主Goroutine可调用Wait()方法阻塞至所有Goroutine结束。
2.1 WaitGroup结构12345// A WaitGroup must not be copied after first use.type WaitGroup struct { noCopy noCopy state1 [3]uint32}
2.2 方法列表
方法名
功能
(wg *WaitGroup) Add(delta int)
等待组的计数器 +1
(wg *WaitGroup) Done()
等待组的计数器 -1
(wg *WaitGroup) ...
Go学习(十八):并发编程-select和通道
1.什么是select?select语句的机制有点像switch语句,不同的是,select会随机挑选一个可通信的case来执行,如果所有case都没有数据到达,则执行default,如果没有default语句,select就会阻塞,直到有case接收到数据。
2. select使用(没有default)如果没有default语句时,select就会阻塞,直到有case接收到数据。
12345678910111213141516171819202122232425262728293031package mainimport ( "fmt" "strconv")func main() { // 创建通道 intChan := make(chan int) stringChan := make(chan string) // 写入 go func() { for i := 1; i < 4; i++ { intChan <- ...
Go学习(十七):并发编程-通道
1.什么是Channel?channel即Go的通道,是协程之间的通信机制。一个channel是一条通信管道,它可以让一个协程通过它给另一个协程发送数据。每个channel都需要指定数据类型,即channel可发送数据的类型。Go语言主张通过数据传递来实现共享内存,而不是通过共享内存来实现数据传递。
2. 创建Channel2.1 语法 channel是引用类型,需要使用make()进行创建。
123456// 声明方式1var cha1 chan 数据类型 cha1 = make(chan 数据类型)// 声明方式2cha1 := make(chan 数据类型)
2.2 使用示例123456789101112131415161718192021package mainimport ( "fmt")type People struct {}func main() { // 创建一个整数型chan intChan := make(chan int) fmt.Printf("intChan类型: %T 值 ...
Go学习(十六):并发编程-协程
1.什么是协程?协程又称为微线程,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程,一个线程也可以拥有多个协程。
协程是编译器级的,进程和线程是操作系统级的。协程不被操作系统内核管理,而完全由程序控制,因此没有线程切换的开销。
2.GoroutineGo语言中的协程叫作Goroutine。Goroutine由Go程序运行时(runtime)调度和管理,Go程序会智能地将Goroutine中的任务合理地分配给每个CPU。创建Goroutine的成本很小,每个Goroutine的堆栈只有几kb,且堆栈可以根据应用程序的需要增长和收缩。
2.1 Coroutine与Goroutine的区别
Goroutine能并行执行,Coroutine只能顺序执行;
Goroutine可在多线程环境产生,Coroutine只能发生在单线程。
Coroutine程序需要主动交出控制权,系统才能获得控制权并将控制权交给其他Coroutine。
Coroutine的运行机制属于协作式任务处理,应用程序在不使用CPU时,需要主动交出CPU使用权。如果开发者无意间让应用程序长时间占用CPU,操作系统也 ...
Go学习(十五):异常处理
1.介绍错误是指程序中出现不正常的情况,从而导致程序无法正常运行。Go语言中没有try...catch来捕获错误,而是通过defer+recover+panic模式来实现捕捉错误信息。
2. error接口2.1 语法Go语言通过内置的错误类型提供了非常简单的错误处理机制,即error接口。该接口的定义如下:
123type error interface { Error() string}
2.2 函数返回错误对于大多数函数,如果要返回错误,大致上都可以定义为如下模式,必须将error作为多种返回值中的最后一个。
1234// 函数返回错误func Demo(参数列表...)(x T, err error){ // 函数体}
2.3 判断错误在Go语言中处理错误的方式通常是将返回的错误与nil进行比较。nil值表示没有发生错误,而非nil值表示出现错误。如果不是nil,需打印输出错误。
1234x,err := Demo(参数列表...)if err != nil { // 打印错误信息....}
2.4 创建e ...
Go学习(十四):面向对象-接口(interface)
虽然 Go 语言没有继承和多态,但是 Go 语言可以通过匿名字段实现继承,通过接口实现多态。
1.介绍1.1 概念在Go语言中,接口是一组方法签名。接口指定了类型应该具有的方法,类型决定了如何实现这些方法。当某个类型为接口中的所有方法提供了具体的实现细节时,这个类型就被称为实现了该接口。接口定义了一组方法,如果某个对象实现了该接口的所有方法,则此对象就实现了该接口。
1.2 声明语法12345type 接口名称 interface { Method1([参数列表]) [返回值列表] Method2([参数列表]) [返回值列表] ...}
示例
123456// 定义一个接口type Bird interface { fly() // 无参数无返回值方法 eat(string2 string) // 有参数无返回值方法 walk(string2 string) string // 有参数有返回值方法}
2.定义和实现2.1 定义接口12345// 定义一个鸟类接口type Birder interfac ...
Go学习(十二):面向对象-结构体(struct)
Go没有沿袭传统面向对象编程中的诸多概念,也没有提供类(class),但是它提供了结构体(struct),方法(method)可以在结构体上添加。与类相似,结构体提供了捆绑数据和方法的行为。
1. 介绍1.1 概念单一的数据类型已经满足不了现实开发需求,于是 Go 语言提供了结构体来定义复杂的数据类型。结构体是由一系列相同类型或不同类型的数据构成的数据集合。结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存。因此必须在定义结构体并实例化后才能使用结构体的字段。
1.2 语法12345type 类型名称 struct { field type field type field1,field2,field3 type // 同类型变量可以写在一行}
1.3 注意事项
类型名是标识结构体的名称,在同一个包内不能重复。
结构体的属性,也叫字段(field),必须唯一。
同类型的成员属性可以写在一行。
结构体是值类型。
只有当结构体实例化时,才能使用结构体的字段。
2. 实例化2.1 使用var1234567891011121314 ...
Go学习(十三):面向对象-方法(method)
Go没有沿袭传统面向对象编程中的诸多概念,也没有提供类(class),但是它提供了结构体(struct),方法(method)可以在结构体上添加。与类相似,结构体提供了捆绑数据和方法的行为。
1.介绍1.1 概念Go语言同时有函数和方法,方法的本质是函数,但是方法和函数又有所不同。
1.2 方法和函数的区别
函数(function)是一段具有独立功能的代码,可以被反复多次调用,从而实现代码复用。
方法(method)是一个类的行为功能,只有该类的对象才能调用。
方法有接受者,而函数无接受者。
函数不可以重名,而方法可以重名。只要接受者不同,方法名就可以相同。
2. 使用2.1 基本语法123func (接收器变量 接收器类型) 方法名(参数列表) (返回值列表) { 函数体}
接收器变量:接收器变量在命名时,官方建议使用接收器类型的第一个小写字母,而不是 self、this 之类的命名。例如: Socket类型的接收器变量应该命名为s,Connector类型的接收器变量应该命名为c等。
接收器类型:接收器类型和参数类似,可以是指针类型和非指针类型。
方 ...
Go学习(十一):映射(map)
1.定义map是一种集合,可以像遍历数组或切片那样去遍历它。因为map是由Hash表实现的,所以对map的读取顺序不固定。
1.1 注意事项
map是无序的,每次打印出来的map都会不一样,它不能通过index获取,而必须通过key获取。返回顺序未知,因此每次打印的顺序可能不一样。
map的长度是不固定的,和切片一样可以扩展。内置的len()函数同样适用于map,返回map拥有的键值对的数量。
同一个map中key必须保证唯一。
key的数据类型必须是可参与比较运算的类型,也就是支持==或!=操作的类型。
引用类型则不能作为key的数据类型。
map的value可以是任何数据类型。
map和切片一样,也是一种引用类型。
map是非并发安全的。
2. 声明语法可以使用var关键字来定义map,也可以使用内建函数make()。
使用var关键字声明map,未初始化的map的默认值是nil,不能存放键值对。如果要使用map存储键值对,必须在声明时初始化,或者使用make()函数分配到内存空间。
2.1 声明初始化12345678910111213141516171819package ma ...
Go学习(十):切片(slice)
1.切片的概念Go语言中数组的长度不可改变,但在很多应用场景中,在初始定义数组时,数组的长度并不可预知,这样的序列集合无法满足要求。Go中提供了另外一种内置类型切片(slice),弥补了数组的缺陷。从底层来看,切片引用了数组的对象。切片可以追加元素,在追加时可能使切片的容量增大。与数组相比,切片不需要设定长度,在 [] 中不用设定值,相对来说比较自由。
2.切片声明使用2.1 通过make1234567//使用make()函数来创建切片var slice1 = make([]int,3)slice1[0] = 1slice1[1] = 2slice1[2] = 4fmt.Printf("通过make关键字创建[slice1] 类型:%T 值:%v \n",slice1,slice1)// 输出: 通过make关键字[slice1] 类型:[]int 值:[1 2 4]
2.2 直接初始化1234// 直接初始化使用slice2 := []int{1,2,4}fmt.Printf("直接初始化使用[slice2] 类型:%T 值:% ...
Go学习(九):数组使用
1.数组的概念数组是相同类型的一组数据构成的长度固定的序列,其中数据类型包含了基本数据类型、复合数据类型和自定义类型。因为数组的内存是一段连续的存储区域,所以数组的检索速度是非常快的,但是数组也有一定的缺陷,就是定义后长度不能更改。
2.声明数组2.1 先声明后使用1234567891011package mainimport "fmt"func main() { // 声明一个长度为3的整型数组 var arr [3]int arr[0] = 1 arr[1] = 3 arr[2] = 5 fmt.Printf("数组arr 类型: %T 值: %v",arr,arr)}// 输出: 数组arr 类型: [3]int 值: [1 3 5]
2.2 直接初始化使用12345678package mainimport "fmt"func main() { // 直接声明使用 arr := [3]int{1,3,5} fm ...
Go学习(八):指针
1.什么是指针?指针是存储另一个变量的内存地址的变量。变量是一种使用方便的占位符,变量都指向计算机的内存地址。一个指针变量可以指向任何一个值的内存地址。
例如:变量a的值为100,存储在内存地址0x1040a124。变量b持有a的地址,则b被认为指向a。如下图
在Go语言中使用取地址符(&)来获取变量的地址,一个变量前使用&,会返回该变量的内存地址。如下程序获取变量a的内存地址
123456789package mainimport "fmt"func main() { a := 1 fmt.Printf("指针地址: %p",&a)}// 输出: 指针地址: 0xc00001c080
Go语言指针的最大特点是:指针不能运算。
2. 声明指针2.1 语法1var 指针变量名 *指针类型
使用示例
12345678910111213141516171819202122package mainimport "fmt"func main() { // 声明一个变量 a := 100 ...
Go学习(七):闭包使用
1. 什么是闭包闭包是由函数和与其相关的引用环境组合而成的实体。在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。函数 + 引用环境 = 闭包。
2. 闭包和函数的区别闭包只是在形式和表现上像函数,但实际上不是函数。具体区别如下:
函数运行时只有一个实例,函数体被定义后就确定了,不会在执行时发生变化。
闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
函数本身不存储任何信息,只有与引用环境结合后形成的闭包才具有记忆性。
函数是编译器静态的概念,而闭包是运行期动态的概念。
3. 使用对比开发一个简易的计数器
3.1 不使用闭包1234567891011121314151617181920212223242526package mainimport "fmt"func main() { // 从一加到十 for i := 1; i< 10; i++ { counter(i) }}// 实现计数器func coun ...
Go学习(六):函数使用
1.函数申明1.1 声明语法12345func funcName( param type ) (output1 type1, output2 type2) { //这里是处理逻辑代码 //返回多个值 return value1, value2 }
1.2 语法解析
func: 函数关键字,
funcName: 指函数名,在同一个包内,函数不能重名。
param: 参数列表;参数列表指定的是参数类型、顺序及参数个数,函数可以包含参数也可以不包含。
output1 type1, output2 type2: 返回值列表,Go语言的函数可以返回多个值。返回值可以是返回数据的数据类型,也可以是变量名+变量类型的组合。
2. 参数接收2.1 参数类型简写在参数列表中,如果有多个参数变量,则以逗号分隔;如果相邻变量是同类型,则可以将类型省略。
使用示例1234567891011121314151617181920212223package mainimport "fmt"func main() { //total,desc := ...