我的go工具箱

一 语法基础

  • 包是一组相关函数和其他代码的组合。
  • 在 Go 文件中使用包的函数之前,需要先导入该包。
  • string 是一系列字节,通常表示文本字符。
  • rune 表示单个文本字符。
  • Go 最常见的两种数字类型是 int(保存整数)和 float64(保存浮点数)。
  • bool 类型保存布尔值,这些值要么为 true,要么为 false。
  • 变量是一段可以包含指定类型值的存储。
  • 如果没有给变量赋值,它将包含其类型的零值。零值的示例包括对 int 或 float64 变量来说是 0,对 string 变量来说是""。
  • 你可以使用:=短变量声明来声明一个变量,并同时为其赋值。
  • 如果变量、函数或类型的名称以大写字母开头,则只能从其他包中的代码访问它们。
  • go fmt 命令自动重新格式化源文件以便使用 Go 标准格式。如果你打算与其他人共享任何代码,你应该对它们运行 gofmt。
  • go build 命令将 Go 源代码编译成计算机可以执行的二进制格式。
  • go run 命令编译并运行一个程序,而不将可执行文件保存在当前目录中。

二 条件和循环

  • 方法是一种与给定类型的值相关联的函数。
  • Go 将从//标记到行尾的所有内容都视为注释,并忽略它。
  • 多行注释以/开头,以/结尾。中间的所有内容,包括换行符,都将被忽略。
  • 传统的做法是在每个程序的顶部都加上一条注释,解释它是做什么的。
  • 与大多数编程语言不同,Go 允许从函数调用或方法调用返回多个值。
  • 多个返回值的一个常见用法是返回函数的主要结果,然后返回第二个值,指示是否有错误。
  • 若要在不使用值的情况下丢弃它,请使用_空白标识符。空白标识符可以用于任何变量的任何赋值语句中。
  • 避免给变量取与类型、函数或包相同的名称,这会使变量遮盖(覆盖)具有相同名称的内容。
  • 函数、条件和循环都有出现在{}大括号中的代码块。
  • 文件和包的代码不出现在{}大括号中,但是它们也包含块。
  • 变量的作用域仅限于它被定义的块内以及嵌套在该块中的所有块。
  • 除了名称之外,导入包时可能还需要包的导入路径。
  • continue 关键字跳转到循环的下一个迭代。
  • break 关键字完全退出循环。

三 函数

  • fmt.Printf 和 fmt.Sprintf 函数格式化给定的值。第一个参数应该是一个包含动词(%d、%f、%s 等)的格式化字符串,其值将被替换。
  • 在格式化动词中,可以包含宽度:格式化值将占用的最小字符数。例如,%12s 的结果是一个 12 个字符的字符串(用空格填充),%2d 的结果是一个 2 个字符的整数,%.3f 的结果是一个四舍五入到小数点后 3 位的浮点数。
  • 如果希望调用函数来接受参数,必须在函数声明中声明一个或多个参数,包括每个参数的类型。所传递的参数的数量和类型必须始终与规定的参数的数量和类型相匹配,否则将出现编译错误。
  • 如果希望函数返回一个或多个值,则必须在函数声明中声明返回值的类型。
  • 不能在函数的外部访问在该函数内声明的变量。但是你可以在函数内访问在该函数外部声明的变量(通常在包级别)。
  • 当函数返回多个值时,最后一个值通常具有一个 error 类型。错误值有一个 Error()方法,该方法返回描述错误的字符串。
  • 按照惯例,函数返回一个错误值 nil,表示没有错误。
  • 你可以通过在指针前面加一个*来访问指针所保留的值:*myPointer。
  • 如果函数接收一个指针作为参数,并更新该指针处的值,那么更新后的值在函数外部仍然可见

四 包

  • 默认情况下,工作区目录是用户主目录中名为 go 的目录。
  • 通过设置 GOPATH 环境变量,可以使用另一个目录作为工作区。
  • Go 在工作区中使用三个子目录:bin 目录保存编译过的可执行程序;pkg 目录保存编译过的包代码;src 目录保存 Go 源代码。
  • src 目录中的目录名用于构成包的导入路径。嵌套的目录名在导入路径中用/字符分隔。
  • 包名由包目录中源代码文件顶部的 package 子句确定。除了 main 包之外,包名应该与包含它的目录名相同。
  • 包名应该都是小写的,理想情况下由一个单词组成。
  • 包的函数只有在导出后才能从包外部调用。如果函数的名称以大写字母开头,则该函数是可导出的。
  • 常量是指一个永远不会改变的值的名称。
  • go install 命令编译包的代码,并将其存储在通用包的 pkg 目录或可执行程序的 bin 目录中。
  • 一个常见的约定是使用包所在的 URL 作为其导入路径。这样在只提供包的导入路径的情况下 go get 工具就可以查找、下载和安装包。
  • go doc 工具显示包的文档。代码中的文档注释也包含在 godoc 的输出中。

五 数组

  • 要声明数组变量,包括方括号中的数组长度以及要保存的元素类型:var myArr [3]int
  • 要赋值或访问数组的元素,在方括号中提供其索引。索引从0开始,因此myArray的第一个元素是myArray[0]。
  • 与变量一样,所有数组元素的默认值都是该元素类型的零值。
  • 可以在创建数组时使用数组字面量设置元素值:[3]int{4,5,6}
  • 如果将对数组无效的索引存储在变量中,然后尝试使用该变量作为索引访问数组元素,你将会收到panic——运行时错误。
  • 可以使用内置的len函数得到数组中元素的个数。
  • 可以使用特殊的for…range循环语法来方便地处理数组的所有元素,该语法循环遍历每个元素,并将其索引和值赋给你提供的变量。
  • 当使用for…range循环时,你可以通过将每个元素的索引或值赋值给_空白标识符来忽略它。
  • os.Open函数打开一个文件。它返回一个指向os.File值的指针,该值代表那个打开的文件。
  • 将os.File值传递给bufio.NewScanner会返回bufio.Scanner值,该值的Scan和Text方法可用于以字符串形式一次从文件中读取一行。

六 切片

  • 同型的切片变量与数组变量的声明相同,只是它忽略了长度:var mySlice []int
  • 在大多数情况下,切片和数组的代码行为完全相同。包括元素赋值、使用0值、传递给len函数和for…range循环。
  • 切片字面量的声明与数组字面量相同,但它忽略了长度:[]int{1,5,8}
  • 你可以获取通过切片运算符s[i:j]获取切片中i到j-1的元素。
  • os.Args包变量包含当前程序执行的命令行参数组成的string类型的切片。
  • 变长参数函数是可以被不同个数的参数调用的函数。
  • 为了声明一个变长参数函数,在最后一个参数之前增加省略号(…)。这个参数就可以以切片的形式接收一组参数。
  • 当调用可变参数函数的时候,可以通过在切片之后追加省略号的方式来代替变长参数:inRange(1,10,mySlice...)

七 Map

  • 声明一个映射变量的时候,你必须提供键和值的类型:var myMap map[string]int
  • 为了创建一个新的映射,调用make函数并传入需要创建的映射的类型:myMap=make(map[string]int)
  • 为了将一个值传入映射,需要提供一个对应的键并用方括号括起来:myMap["myKey"]=12
  • 为了获取值,你需要像上面一样提供一个键:fmt.Println(myMap["mykey"])
  • 你可以使用映射字面量来创建和初始化一个映射:map[string]int{"a":2,"b":3}
  • 与数组和切片相同,如果你访问一个还没有赋值的值,你会获得零值。
  • 从映射中获取一个值能得到第二个可选的布尔值,用来标识这个值是否被赋值过,还是这个值就仅仅代表一个零值:val,ok:=myMap["c"]
  • 如果你想要测试一个键是否被赋值过,你可以使用_空白标识符来忽略真实的值。_,ok:=myMap["c"]
  • 你可以通过delete内建函数来删除键和它对应的值:delete(myMap,"b")
  • 你可以像在数组和切片中使用for…range循环一样来使用映射。你需要提供两个变量,每轮中,第一个变量获取键的值,另一个变量获取值的值。
for key,value:=rang myMap{
  fmt.Println(key,value)
}

八 struct

  • 你可以使用struct类型声明一个变量。使用struct关键字定义一个struct类型,后面跟着花括号和其中的一组字段名称和类型。
var myStruct struct{
  field1 string
  field2 int
}
  • 重复写struct类型很乏味,所以经常基于一个基础类型来定义一个类型。然后使用定义好的类型来创建变量、函数参数和返回值。
type myType struct{
  field1 string
}
var myvar myType
  • 通过点运算符来访问struct字段。
myVar.field1="value"
fmt.Println(myVar.field1)
  • 如果函数需要修改struct或者struct过大,应该向函数传递指针。
  • 如果类型想要在定义它的包之外使用,它的首字母应该大写。
  • 同理,如果strcut字段想要在包外被访问,它们名称的首字母需要大写。
  • struct字面量让你可以同时创建struct和设置它的字段值。myVar:=myType{field1:"value"}
  • 在struct字段列表中增加一个类型,没有名字,定义了一个匿名字段。
  • 使用匿名字段的方式将内部struct增加到外部struct被称为嵌入了外部struct。
  • 你可以像访问外部字段一样访问嵌入的strcut字段。

九 定义类型

  • 一旦你定义了类型。你可以从相同基础类型转换:Gallons(10.0)
  • 一旦一个变量的类型被定义,其他类型的值不能再赋给该变量,即使它们有相同的基础类型。
  • 一个定义的类型支持与基础类型相同的运算符。例如一个基于int的类型,能够支持+、-、*、/、==、>和<运算符。
  • 一个定义的类型可以与字面值一起运算:Gallons(10.0)+2.3
  • 在函数名称前放入一个在括号中的接收器参数来定义一个方法:
func (m MyType) MyMethod(){

}
  • 接收器参数可以像其他参数一样在方法内部被调用:
func (m MyType) MyMethod(){
 fmt.Println("called on ",m)
}
  • 与函数一样,你可以为方法定义一个额外的参数或者返回值。
  • 在同一个包中定义多个同名的函数不被允许,即使它们有不同类型的参数。你可以定义多个相同名字的方法,只要它们分别属于不同的类型。
  • 你只能为同包的类型定义方法。
  • 就像其他的参数一样,接收器参数接收一个原值的拷贝。如果你的方法需要修改接收器,你应该在接收器参数上使用指针类型,并且修改指针指向的值。

十 封装和嵌入

  • 在Go中,数据被封装在包内,使用未导出的包内变量和结构字段。
  • 未导出的变量、struct字段、函数、方法等可以被相同包中的导出的函数和方法访问。
  • 在接受数据之前先确保数据有效的做法称为数据校验。
  • 一个主要用来设置封装字段的方法称为setter方法。setter方法通常包含校验逻辑,以确保提供的值是合法的。
  • 由于setter方法修改它们的接收器,接收器参数应该是一个指针类型。
  • setter方法通常被命名为SetX,X是被设置字段的名称。
  • 一个主要被用来获取封装字段值的方法被称为getter方法。
  • 通常getter方法命名为X,X就是获取的值的字段名称。一些其他的编程语言喜欢使用GetX作为getter方法的名字,但在Go中不推荐。
  • 外部类型定义的方法和内部嵌入类型的方法的生存时间是一样的。
  • 一个嵌入类型的未导出方法不会被提升到外部类型。

十一 接口

type Vehicle interface{
  Accelerate()
  Brake()
  Steer(string)
}
  • 一个具体类型定义不仅指示了值能做什么(哪些方法可以被调用),也表明了它们是什么:它们定义了保存值数据的基础类型。
  • 一个接口类型是一个抽象类型。接口并不会描述值是什么:它们不会说基础类型是什么或者数据是如何保存的。它们仅仅描述值能做什么:它具有哪些方法。
  • 一个接口定义需要包含一组方法名称,以及方法的参数和返回值。
  • 为了满足一个接口,类型必须实现接口定义的所有方法。方法名称、参数类型(或没有)和返回值类型(或没有)都必须与接口中定义的一致。
  • 除了接口的方法之外,类型可以有其他的方法,但是它不能缺少接口中的任何方法。否则,类型就不满足那个接口。
  • 类型可以满足多个接口,接口也可以被不同的类型满足。
  • 接口满足是自动的。不需要显式声明具体类型满足Go中的接口。
  • 当有一个接口类型的变量时,你能在它之上调用的方法只能是接口定义的。
  • 如果你将一个具体类型赋值给接口类型的变量,你能使用类型断言来获得具体类型的值。只有这样你才能调用具体类型定义的(但没有定义在接口中的)方法。
  • 类型断言返回第二个bool值来表明断言是否成功。car,ok:=vehicle.(Car)

十二 从异常中恢复

  • 从带有错误值的函数中提前返回是指明错误发生的好方法,但它阻止了之后函数中的清理代码的运行。
  • 可以使用defer关键字在需要清理的代码之后立即调用清理函数。这将清理代码设置为,在当前函数退出时,无论是否存在错误都将运行。
  • 你可以调用内置的panic函数来引发程序panic。
  • 除非调用内置的recover函数,否则panic的程序将崩溃并显示日志信息。
  • 你可以将任何值作为参数传递给panic。该值将被转换为字符串并作为日志信息的一部分打印出来。
  • panic日志信息包括堆栈跟踪,即所有活动的函数调用列表,这些对于调试非常有用。
  • 当程序陷入panic时,仍然会执行任何延迟的函数调用,从而允许在崩溃之前执行清理代码。
  • 延迟的函数也可以调用内置的recover函数,这将使程序恢复正常运行。
  • 如果在没有panic时调用recover,它只返回nil。
  • 如果在panic期间调用recover,它将返回传递给panic的值。
  • 大多数程序只有在出现意料之外的错误时才会出现panic。你应该考虑程序可能遇到的所有错误(例如文件丢失或格式错误的数据),并使用error值来处理这些错误

十三 goroutine 和channel

  • 所有Go程序都至少有一个goroutine:程序启动时调用main函数的那个goroutine。
  • Go程序在main goroutine停止时结束,即使其他goroutine尚未完成其工作。
  • time.Sleep函数将当前goroutine暂停一段时间。
  • Go不保证何时在goroutine之间切换,或者它将持续运行一个goroutine多长时间。这允许goroutine更高效地运行,但这意味着你不能指望按特定顺序执行操作。
  • 函数返回值不能在go语句中使用,部分原因是当调用函数试图使用它时,返回值还没有准备好。
  • 如果需要goroutine中的值,则需要将其传递给一个channel,以便将该值发送回来。
  • channel是通过调用内置的make函数创建的。
  • 每个channel只携带一种特定类型的值,在创建channel时指定该类型。myChannel:=make(chan MyType)
  • 使用<-运算符将值发送给channel:myChannel<-"a value"
  • <-运算符也用于从channel接收值:value:=<-myChannel

十四 测试

  • 自动化测试使用一组特定的输入运行代码,并寻找特定的结果。如果代码输出与期望值匹配,则测试“通过”;否则,测试“失败”。
  • go test工具用于运行测试。它在指定的包中查找文件名以_test.go结尾的文件。
  • 你不需要将测试与正在测试的代码放在同一个包中,但是这样做将允许你访问该包中未导出的类型或函数。
  • 测试需要使用testing包中的类型,所以你需要在每个测试文件的顶部导入该包。
  • 一个_test.go文件可以包含一个或多个测试函数,它们的名字以Test开头。名字的其余部分可以是你想要的任何内容。
  • 测试函数必须接受单个参数:一个指向testing.T值的指针。
  • 测试代码可以对包中的函数和方法进行普通调用,然后检查返回值是否与预期值匹配。如果不匹配,测试失败。
  • 你可以通过对testing.T值调用方法(例如Error)来报告测试失败。大多数方法都接受一个字符串,其中包含解释测试失败原因的信息。
  • Errorf方法的工作原理类似于Error,但是它接受格式化字符串,就像fmt.Printf一样。
  • _test.go文件中名字不以Test开头的函数不会由go test运行。它们可以被测试用作“helper”函数。
  • 表驱动测试是处理输入和预期输出的“表”的测试。它们将每一组输入传递给正在测试的代码,并检查代码的输出是否与预期值匹配。

十五 web应用程序

HTTP处理
程序函数
net/http处理程序函数是用来处理浏览器对特定路径的请求的函数。处理程序函数接收http.ResponseWriter值作为参数。处理程序函数应该使用ResponseWriter写出响应。
一级函数
在具有一级函数的语言中,可以将函数赋值给变量,然后使用这些变量来调用函数。当调用其他函数时,函数也可以作为参数传递。

  • net/http包的ListenAndServe函数在指定的端口上运行Web服务器。
  • localhost主机名处理从计算机到自身的连接。
  • 每个HTTP请求都包含一个资源路径,该路径指定浏览器正在请求服务器的多个资源中的哪一个。
  • HandleFunc函数接受一个路径字符串,以及一个处理该路径请求的函数。
  • 你可以反复调用HandleFunc来为不同的路径设置不同的处理函数。
  • 处理函数必须接受一个http.ResponseWriter值和一个指向http.Request值的指针来作为参数。
  • 如果对使用byte的切片的http.ResponseWriter调用write方法,该数据将被添加到发送到浏览器的响应中。
  • 可以保存函数的变量具有函数类型。
  • 函数类型包括函数接受的参数的数量和类型(或没有),以及函数返回的值的数量和类型(或没有)。
  • 如果myVar包含一个函数,你可以通过在变量名后面加上括号(包含函数可能需要的任何参数)来调用该函数。

十六 Html模板

模板text/template包接受一个模板字符串(或从文件加载的模板),并将数据插入其中。html/template包的工作方式与text/template类似,只是它还提供了使用HTML所需的安全保护。

  • 模板字符串包含将逐字输出的文本。在此文本中,可以插入含有将被计算的简单代码的各种action。可以使用action将数据插入模板文本中。
  • Template值的Execute方法接受一个满足io.Writer接口的值,以及可以在模板的action中访问的数据值。
  • 模板action可以引用传递给使用{{.}}的Execute的数据值,简称“点”。点的值可以在模板的不同上下文中变化。
  • 在{{if}}action与其对应的{{end}}标记之间的模板部分,只有在某个条件为真时才会被包含。
  • 在{{range}}action与其对应的{{end}}标记之间的模板部分,将对数组、切片、映射或channel中的每个值重复。该部分中的任何操作也将被重复。
  • 在{{range}}节中,点的值将被更新为指向正在处理的集合中的当前元素。
  • 如果点指向一个struct值,则可以用{{.FieldName}}插入该struct中的字段值。
  • 当浏览器需要从服务器获取数据时,通常使用HTTP GET请求。
  • 当浏览器需要向服务器提交新数据时,将使用HTTP POST请求。
  • 可以使用http.Request值的FormValue方法访问来自请求的表单数据。
  • 可以使用http.Redirect函数来引导浏览器请求不同的路径。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值