本篇内容主要是对于Go语言的基础及其相关特殊性语法进行总结。
- 字符串的拼接只能拼接字符串的变量,如果将整数和字符串进行拼接将导致编译错误。
- 如果需要在循环中拼接字符串,则使用空的字节缓冲区来拼接的效率会更高。
for i := 0; i < 500; i++ { buffer.WriteString("z") } fmt.Println(buffer.String) //创建一个空的字节缓冲区,并将其值赋给变量buffer //一个运行500次的循环,每次循环都将字符串z写入缓冲区 //循环结束后,对缓冲区调用函数String()以字符串的方式输出结果。
- Go语言中的字符串实际上是只读的字节切片。注意是只读,这意味着创建之后就不能修改。
s := "hello" fmt.Println("%q", s[0]) // 'h' fmt.Println("%b", s[0]) //1101000 fmt.Println(s[0]) //104 //通过索引访问字符串时,访问的是字节而不是字符,因此显示的是十进制表示的字节值
- 将字符串转换为小写。
fmt.Println(string.ToLower("SKLL"))
- 查找子串。方法Index接受的第二个参数是要查找的子串,如果找到就返回第一个子串的索引号,如果没有找到,就返回-1。
import ( "fmt" "string" ) func main() { fmt.Println(string.Index("surface", "face")) }
- Go将错误作为一种类型,一种约定是在调用可能出现问题的方法或函数时,返回一个类型为错误的值。这意味着如果出现问题,函数通常不会引发异常,而让调用者决定如何处理错误。
- Go语言支持两种创建字符串字面量的方式:解释型字符串字面量使用双引号括起的字符如“Hello”,除换行符和未转义的双引号外,解释型字符串字面量可以包含其他任何字符,对于前面有反斜杠(\)的字符,将使用rune字面量中进行解读;原始字符串字面量用反引号括起,`Hello`,不同于解释型字符串,原始字符串中的反斜杠没有特殊含义,Go按原样解释这种字符串。
- 在Go语言中,有一种约定是,如果没有发生错误,则返回的错误值是nil。
- 标准库中的errors包支持创建和操作错误,Errorf可以用于设置返回的错误字符串格式。
err := errors.New("ssss") err := fmt.Println("The %v %v quit", r, n)
- 除了从技术角度考虑Go语言的错误处理方式和错误生成方式外,还需要从以用户为中心的角度考虑错误。
- panic函数将程序停止运行,没有任何回旋的余地。
panic("goodbye")
- Goroutine是应对网络延迟的方式之一。使用起来非常简单,只需在要让Goroutine执行的函数或方法前面加上关键字go。
- 并发和并行的差别。并发就是同时处理很多事情,并行就是同时做很多事情。比如同时烤多个饼称为并发,将烤饼任务分为两家烤,烤完再放在一起称为并行。
- 如果说Goroutine是一种支持并发编程的方式,那么通道就是一种与Goroutine通信的方式。
- 在其他编程语言中,并发变成通常是在多个进程或线程之间共享内存实现的。但这可能会引发Bug或导致程序崩溃,因为通过这种方式需要给内存加锁,确保只有一个进程或线程能够访问它。并且共享内存和锁的管理工作并非那么容易。
- Go使用通道在Goroutine之间收发消息,避免使用共享内存。通过收发消息,使得能够以推送的方式协调并发事件。
//创建通道,关键字chan后面的string指出这个通道将用于存储字符串数据 c := make(chan string) //向通道发送消息 c <- "ho" //从通道接受消息 msg := <- c
- 使用缓冲通道,将数据存储在通道中,等接收者准备就绪再交给它。close用来关闭通道,禁止再向通道发送消息。
//创建一个可存储两条消息的缓冲通道。 msg := make(chan string, 2) close(msg) //函数receiver使用range迭代通道,并将通道中缓冲的消息打印到控制台。 receiver(msg)
- <-位于关键字chan左边时,表示通道在函数内是只读的;<-位于关键字chan右边时,表示通道在函数内是只写的;没有指定<-时,表示通道是可读写的。
func chanel(message <- chan string){ //只读 } func chanels(message chan <- string){ //只写 } func chanelss(message chan string){ //读写 }
- 假设有多个Goroutine,而程序将根据最先返回的Goroutine执行相应的操作,此时可使用select语句。如果同时从两个通道收到消息,将会随机选择并执行一条case。收到一条消息后,select语句将不再堵塞。
select { case msg1 := chan1: fmt.Println("ss") case msg2 := chan2: fmt.Println("xx") case <- time.Afer(500 * time.Millisecond): fmt.Println("cc") //超时时间,可使得select不再堵塞。+ }
- 在已知需要停止执行的时间情况下,使用超时时间是不错的选择,但在有些情况下,不确定select语句在何时返回,因此不能使用定时器,在这种情况下,使用退出通道,向其发送消息,让select语句停止堵塞。
- Go程序以package语句开头。main包是一种特殊的包,其特殊之处在于不能导入。对main包唯一的要求是,必须声明一个main函数,这个函数不接受任何参数且不返回任何值。在main包中,可使用import声明来导入其他包。导入包后,就可以使用其中被导出的标识符。
- 命令go get会自动下载依赖的第三方包。
- Go1.5引入文件夹vendor,将第三方模块添加到项目目录下文件夹vendor中,并将所有包都移到这个文件夹中,这样可以不全局的安装包。
- 关于要发布到网上的包,推荐包含三个文件:指出用户如何使用代码的LICENSE文件;包含有关包的说明信息的README文件;详细说明包经过哪些修改的Changelog文件。
- Go语言没有提供包签名,因此攻击者可能会破解Github账户,在包中执行恶意代码,所以使用第三包要谨慎。
- 命令gofmt可设置代码格式。
- godoc通过分析源代码和注释生成文档。
- 在接口命名方面,惯用的做法是使用一个动词,并在末尾加上er。
- 新加入项目的开发人员通常可通过阅读测试来了解程序的运行方式:单元测试,功能测试和集成测试。单元测试指出,如果给函数x提供这些值,应该返回那个值,确认程序最小构件按照期望的方式运行;集成测试检查的是应用程序各个组件协同工作的情况;功能测试从最终用户的角度核实软件按照期望的那样工作。
- 为支持测试,Go语言在标准库中提供了testing包。测试不是放在独立的测试目录中,而是与它们要测试的代码放在同一个目录中。测试文件的名称后面加上后缀_test。第二个约定是,测试为名称以单词Test打头的函数。
- Go语言提供了表格驱动测试模式,能够同时测试很多条件。
package example import "testing" type Gree struct { name string locale string want string }//创建一个结构体,用户存储编写测试所需要的数据 var greetingTests = []GreetingTest{ {"a", "b", "c"}, {"a", "g", "k"}, }//创建一个切片,存储测试的情形 func TestGreeting(t *testing.T){ for _, test := range greetingTests { got := Greeting(test.name,test.locale) if got != test.want{ t.Errorf(xxx) } } }
- Go提供了基准测试框架,能够让我们使用基准测试程序来确定完成特定任务时性能最佳的方式。
- 测试覆盖率是度量代码测试详尽程度的指标,它指出了被测试执行了的代码所在的百分比值。
- 日志指的是程序执行期间发生的情况。无论程序需不需要调试,都会产生日志。Go提供了log包,让应用程序能够将日志写入终端或文件。
import "log" func main() { log.Printf("x") }
- 结合使用动词v和+可打印结构体中字段的名称。
fmt.Printf("%+v\n", someStruct)
- Delve让开发人员能够与正在执行的程序交互,进入正在运行的进程以及查看核心转储和栈跟踪。