Golang学习杂记

原作者视频地址:
https://www.bilibili.com/video/BV11Y4y1a7Jo?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click
本人为自学整理的文档

  1. FprintXX(写到响应流,输出控制台) SprintXX(返回字符串,不输出控制台)
    Fprintf(根据格式输出) Fprintln(输入换行符)
    Println如果是输出单个字符就是输出字符对应的数字,输出字符串就是对应字符串
  2. 十进制/十六进制/二进制:%d %x或%X %b
    浮点/布尔/字符/字符串/带双引的字符串/输出类型/内存地址
    %f %t %c %s %q %T %p
  3. 输入:scanfln;常量生成器:iota(无论在哪里都是从0开始递增);在go语言中数值是值类型,数组名不是指向第一个变量;切片是引用类型,相当于指针,和数组定义的方法差不多,只是不写大小,而且定义时是不开辟内存空间的,初始化后才有;切片赋值是赋地址
  4. append扩容机制:往切片添加一定数量的元素时,如果添加后大于切片容量需要翻倍扩容,进一步如果扩容后还是小,就使容量等于当前数量
  5. 用数组产生切片时,切片的地址是对应 取出数组待取首元素的地址,如果后续添加元素到切片至超出原数组后面的连续空间,就会为整个切片生成新的地址
  6. Goland的环境配置:
    1.点首页左上角File->New->Project
    2.再点击File->Setting->Go->GoPath->弹窗的左上“+”->选择刚刚新建项目
    3.回到界面点击新建的项目->新建文件src/main.go->src里新建很多自定义库文件->在库文件再定义go文件写代码
    自定义包配置问题:一般都用go mod来引入依赖包,每次新建一个新的项目就在其路径下执行【go mod init 项目名】,然后再go mod tidy
  7. 结构体: type 结构体名 struct{}
    结构体指针用 new(结构体名称) 生成
    map只声明是空指针
  8. 方法:区别于函数func (结构体/结构体指针类型变量名 结构体/结构体指针) 方法名;函数就是简单的函数,方法就是带接受者的函数,至于接口:接口是虚的
    函数:对应操作序列,是程序的基本组成元素。
    函数有具名和匿名之分:
    具名函数一般对应于包级的函数,是匿名函数的一种特例,当匿名函数引用了外部作用域中的变量时就成了闭包函数,闭包函数是函数式编程语言的核心。方法是绑定到一个具体类型的特殊函数,Go语言中的方法是依托于类型的,必须在编译时静态绑定。具名函数就是普通的func 函数名(输入参数)返回值{函数体}。
    匿名函数是将上述那样的具名函数赋给一个变量,那个变量就可以像调用具名函数那样使用,只不过是将函数名改成变量名,这其中隐含了:函数可以作为一个右值赋给一个变量。
    方法:定义类型添加一个或多个方法。每种类型对应的方法必须和类型的定义在同一个包中,因此是无法给 int 这类内置类型添加方法的(因为方法的定义和类型的定义不在一个包中)。对于给定的类型,每个方法的名字必须是唯一的,同时方法和函数一样也不支持重载。
    方法和函数差不多,只不过多了一个接收者在func后面。
    接口:是对某一组操作的抽象。接口中只有方法声明(这里的方法只能有函数名、参数和返回值,不带接收者–>相当于写去掉func的函数?),然后后面如果哪个结构体想要有这个方法,就直接按普通的方法实现流程那样进行实现,注意一组新定义的接口不要包括之前定义过的接口里的函数(如函数A),毕竟有封装性的问题,可以考虑将函数A从前的接口中拿出来,再定义一个新的接口装这个函数,然后后面需要用到这个函数的新接口就直接添加函数A的接口名即可。
//例如
type Eat interface {
	Eat()
}
type Live interface {
	Run(runmeter int)//这个是新函数
	Eat//由于封装性的特定,这个接口用前面的接口
}
  1. 继承:
    1.将其他结构体当成构建结构体的一部分。
    2.结构体的几种关系:继承(强耦合)、实现(接口和实现类)、依赖(将一个结构体作为另一个结构体的参数)、关联(强依赖和平等)、聚合(整体和部分)、组合(整体和部分,不可分和同周期)
    组合>聚合>关联>依赖
    3.在go中用匿名属性实现继承
//例如:
type People struct {
     name string
}
type Teacher struct {
     classroom string
     People
}
  1. 封装:
    1.最直接的就是函数名首字母大小写,大写才能被其他包调用,小写只能在所在包调用。
    2.对另一个包下的参数调用,在那个包下实现设置、取值的相关方法以供外部调用,不然无法访问结构体里的参数。
  2. 多态:
    1.多态就是接口的用法表示,接口就是一组操作的声明,然后后面再按方法的实现来完成不同结构体下的实现基于接口的多态。
    2.多态在代码层面最常见的就是将接口当做方法参数
    在这里的话说明一下我当前对接口类型的理解:
    除了基本数据类型,复合类型指针pointer、数组array、切片slice、字典map、channel,
    结构体struct和接口interface其实有点像?因为go也说了只要一个结构体实现了接口的全部方法,这个结构体就属于接口类型了,映射到代码上就是这个结构体的变量可以作为一个整体赋给接口变量,然后接口变量调用接口方法时,具体调用哪个方法就看赋值的结构体是哪种类型,实现出来就是那种类型下的接口方法。
    注意:因为interface也是一个类型,上面接口类的接口方法要按函数/方法那样写出来
package InterfaceTest

import "fmt"

type People struct {
	name string
}
type Animate struct {}
type Live interface {
	run()
}
func (p *People) run() {
	fmt.Println("执行people的run")
}
func (a *Animate) run() {
	fmt.Println("执行Animate的run")
}
func Allrun(live Live)  {
	live.run()
}
package main

import "myItem/src/InterfaceTest"

func main() {

	//接口测试2
	peo := &InterfaceTest.People{}
	ani := &InterfaceTest.Animate{}
	InterfaceTest.Allrun(peo)
	InterfaceTest.Allrun(ani)
	}
  1. 如果一个接口没有方法,那么这个接口类型的变量可以接收任何类型的值,因此可以用来做类型检查,具体操作:
    var i interface{} := 123
    _,ok := i.(int)//通过这行代码可以有:如果i被赋予int型,则返回被赋予的数值和bool类型的true
    panic抛出异常,后面的代码不执行(defer除外),recover相当于取消panic,一般recover都在defer里,所以panic后面的函数还是不会执行的
    defer是所有程序执行后再执行的,常用于关闭数据库之类的操作,用法就是defer func(){函数体}()//匿名函数
    多个defer是按照栈的形式存储的,先产生的后执行,如果defer和return同时存在时,先执行return后面的操作,再执行defer后面的操作,最后再退出

------>5.28补充<------
channel在多并发操作里是属于协程安全的,并且遵循 FIFO 特性,即先执行读取的 goroutine 会先获取到数据,先发送数据的 goroutine 会先输入数据。
无缓冲channel先写再读,先假定有两个goroutine:G1和G2,G1往channel写数据,而由于 channel 是无缓冲的,所以 G1 暂时被挂在 sendq队列里,然后 G1 调用了 gopark 休眠了起来。之后G2来channel 读取数据,此时 G2 发现 sendq 等待队列里有 goroutine 存在,于是直接从G1 copy 数据过来,并且会对 G1 设置 goready 函数,这样下次调度发生时, G1 就可以继续运行,并且会从等待队列里移除掉。
无缓冲channel先读再写,G1往channel读数据,G1 暂时被挂在了 recvq 队列,然后休眠起来,之后G2 在写数据时,发现 recvq 队列有 goroutine 存在,于是直接将数据发送给 G1,同时设置 G1 goready 函数,等待下次调度运行。
有缓冲channel先写再读,先判断缓冲数据区域是否已满,如果未满,则将数据保存在缓冲数据区域里。如果已满就和之前的流程是一样的。当 G2 要读取数据时,会优先从缓冲数据区域去读取,并且在读取完后,会检查 sendq 队列,如果 goroutine 有等待队列,则会将它上面的 data 补充到缓冲数据区域,并且也对其设置 goready 函数。
有缓冲channel先读再写和无缓冲的先读再写是一样的。

Go Web开发基础(内容和截图均来自于书籍:《Go Web编程实战派——从入门到精通》)

客户端浏览器处理

  1. 用户打开客户端浏览器,输入URL地址,客户端浏览器会通过HTTP协议向服务端发送浏览请求,服务器端就会通过CGI程序接收请求,如果在客户端浏览器请求的资源包中不含动态语言的内容,则服务器端CGI程序直接通过HTTP协议向客户端浏览器发送应答包;若含动态语言的内容,服务器会调用动态语言的解析引擎处理“动态内容”,用CGI程序访问数据库并处理数据,之后再通过HTTP协议将处理得到的数据返回客户端浏览器。
  2. DNS解所的简要过程如下:
    (1)用户打开浏览器,输入URL地址。浏览器从接收到的URL中抽取出“域名”字段(即要访问的主机名),并将这个主机名传送给DNS应用程序的客户端。
    (2)DNS客户端向DNS服务器端发送一份查询报文,其中包含要访问的主机名字段。
    (3)DNS服务器端给DNS客户端发送一份回答报文,其中包含该主机名对应的IP地址。
    (4)该浏览器在收到来自DNS的IP地址后,向该IP地址定位的HTTP服务器发起TCP连接。
    (注:客户端与服务器端之间的通信是非持久连接的,服务器端发送应答后就断开连接)
  3. HTTP请求:请求消息由请求行、请求头和请求体组成;请求行由请求方法、URL、HTTP协议/协议版本组成;请求头包含服务器要使用的附加信息。请求体是指在HTTP请求中传递数据的实体。
  4. URI(Uniform Resource Identifier,统一资源标识符):用来标识Web上每一种可用资源,概念。由资源的命名机制、存放资源的主机名、资源自身的名称等组成。
    URL(Uniform Resource Locator,统一资源定位符):用于描述网络上的资源(描述信息资源的字符串),实现。使用统一格式,包括文件、服务器地址和目录等。
  5. template包(html/template)
    ParseFiles函数创建一个模板并解析filenames指定的文件里的模板定义。返回的模板的名字是第一个文件的文件名(不含扩展名),内容为解析后的第一个文件的内容。至少要提供一个文件。如果发生错误,会停止解析并返回nil
    ParseGlob创建一个模板并解析匹配pattern的文件(参见glob规则)里的模板定义。返回的模板的名字是第一个匹配的文件的文件名(不含扩展名),内容为解析后的第一个文件的内容。至少要存在一个匹配的文件。如果发生错误,会停止解析并返回nil。ParseGlob等价于使用匹配pattern的文件的列表为参数调用ParseFiles。
    Delims方法用于设置action的分界字符串,应用于之后的Parse、ParseFiles、ParseGlob方法。嵌套模板定义会继承这种分界符设置。空字符串分界符表示相应的默认分界符:{{或}}。返回值就是t,以便进行链式调用。
    Parse方法将字符串text解析为模板。嵌套定义的模板会关联到最顶层的t。Parse可以多次调用,但只有第一次调用可以包含空格、注释和模板定义之外的文本。如果后面的调用在解析后仍剩余文本会引发错误、返回nil且丢弃剩余文本;如果解析得到的模板已有相关联的同名模板,会覆盖掉原模板。
    Execute方法将解析好的模板应用到data上,并将输出写入wr。如果执行时出现错误,会停止执行,但有可能已经写入wr部分数据。模板可以安全的并发执行。
    ExecuteTemplate方法类似Execute,但是使用名为name的t关联的模板产生输出。
  6. 模板使用流程:
    (1)定义模板文件
    按照相应语法规则去定义。
    (2)解析模板文件
    创建指定模板名称的模板对象
func New(name string) (*Template)

解析模板内容

func (t *Template) Parse(src string) (*Template, error)

解析模板文件

func ParseFiles(filenames...string) (*Template, error)

正则匹配解析文件,template.ParaeGlob(“a*”)

func ParseGlob(pattern string) (*Template, error)

(3)渲染模板文件

func (t *Template) Execute(wr io.Writer, data interface{}) error
//配合ParseFiles()函数使用,需指定模板名称
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error
  1. 处理HTML表单
    HTML表单的enctype属性决定表单的内容类型(content type)。
    (1)application/x-www-form-urlencoded
    表单的默认编码,表单中的数据编码为键值对,且所有字符会被编码(空格转换为“+”号,特殊符号转换为ASCII HEX值)。
    method方法为GET时,表单数据转换为"nam1=value1&name2=value2&…“,拼接到URL后面,”?"分隔。加密采用的编码字符集取决于浏览器。method方法为POST时,数据添加到HTTP Body中,浏览器根据网页的ContenrType(“text/html; charset=UTF-8”)对表单数据编码。
    (2)multipart/form-data
    上传二进制文件,不对字符编码,POST方式。对表单以控件为单位分隔,每部分加上Content-Disposition(form-data|file)、Content-Type(默认text/plain)、name(控件name)等信息,并加上分隔符(边界boundary)。
    (3)text/plain
    向服务器传递大量纯文本信息,空格转换为加号(+),不对特殊字符编码。
    Form字段支持URL编码,键值来源是URL和表单。
    PostForm字段支持URL编码,键值来源是表单,只用于获取表单键值。
  2. session和cookie
    session和cookie用于弥补HTTP的无状态特性(每次请求无记录),服务器端第一次收到请求,开辟session空间(创建session对象),同时生成sessionId,通过"Set-Cookie: JSESSIONID=XXXXXX"发给客户端。客户端收到响应后,设置JSESSIONID=XXXXXX的cookie信息,cookie过期时间为浏览器会话结束。以后客户端请求,添加cookie信息(含sessionId),服务器端读取请求头中cookie信息,获得JSESSIONID,sessionId。
    cookie用作一般客户端存储,随每个请求发送,降低性能。客户端可以选择禁用cookie,无法禁用服务器端的session。
    session能够存储任意类型的对象,cookie只能存储String类型对象。
  3. Go Web服务器请求和响应的流程如下:
    (1)客户端发送请求;
    (2)服务器端的多路复用器收到请求;
    (3)多路复用器根据请求的URL找到注册的处理器,将请求交由处理器处理;
    (4)处理器执行程序逻辑,如果必要,则与数据库进行交互,得到处理结果;
    (5)处理器调用模板引擎将指定的模板和上一步得到的结果渲染成客户端可识别的数据格式(通常是HTML格式);
    (6)服务器端将数据通过HTTP响应返回给客户端;
    (7)客户端拿到数据,执行对应的操作(例如渲染出来呈现给用户)。
  4. Go Socket编程
    服务器端和客户端通过Socket通信,服务器端Socket监听地址,等待客户端来连接。客户端Socket连接客户端Socket。
    建立TCP/IP连接的过程,产生三次网络通信,三次握手;关闭TCP/IP连接的过程,产生四次网络通信,四次握手。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜以冀北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值