Go语言学习笔记这一堆主要是《Go语言编程》(人民邮电出版社)的读书笔记。中间会穿插一些零碎的点,比如源码学习之类的。大概就是这样吧。
1. 顺序编程
1.1 变量
变量的声明:
var 变量名 类型
var v1 int
也可以把若干变量的声明用大括号括起来
var { v1 int v2 string }
变量初始化:
变量的初始化可以用如下的方法:
var v1 int = 10 var v2 = 10 v3 := 10
这三种方法的效果大体上是一样的。需要注意的有:第三种方法不能用于声明全局变量;以及:=赋值符号不能用于已声名过的变量名。
变量的赋值:
赋值这里唯一特别的是,Go语言支持多重赋值,比如交换i和j的值:
i, j = j, i
匿名变量:
Go语言有一个特性,就是在引入的包和变量在没有使用的时候,会在编译阶段报错。所以对于不需要的变量,可以使用匿名变量进行处理。
两个例子,第一个是多重返回函数的返回值的处理:
func GetName() (firstName, lastName, nickName string) { return "May", "Chan", "Chibi Maruko" } _, _, nickName := GetName()
如果只需要函数的部分返回值的时候,就可以利用匿名变量。
第二个是for循环:
var a int[] = {5, 4, 3, 2, 1} for _, value := range(a) { balabala }
当我们不需要range返回的部分结果的时候,就可以利用匿名变量。
1.2 常量
字面常量:大概只有一点要说,就是不需要额外做特别的声明。比如对于long类型的12,不存在12l这种写法。
常量定义:通过const关键字进行定义。
const Pi float64 = 3.1415926
需要注意的大概有:声明的时候可以不限定类型;常量定义的右值也可以是编译期运算的常量表达式。
const Zero = 0.0 const mask = 1 << 3 const Home = os.GetEnv("HOME")
这里第三句会导致错误。因为右值只有在运行期才能知道结果。
预定义常量:true,false,iota。
这里true和false没有什么说的。
iota可以被认为是一个可被编译器修改的常量,该常量在每一个const关键字出现的时候被重置为0。在下一个const出现之前,每出现一次iota,其所代表的数字自动加1。
Golang不支持enum关键字的枚举类型,通常把const和iota结合起来表示枚举,例如:
const { Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday numberOfDays }
这样就将星期与整数对应了起来。
注意,numberOfDays并没有被导出。
1.3 类型
Golang支持以下类型:
基本类型:布尔型,整型,浮点型,复数型,字符串,字符型,错误型。
复合类型:指针,数组,切片,字典,通道,结构体,接口。
基本类型中,需要注意的问题如下;
int和int32在Golang中被认为是不同的两个类型。所以二者不能互相赋值(编译期不会自动做类型转换),需要进行强制的类型转换。
自动推导的浮点数类型是float64。
复数类型是其他大部分语言不支持的。例子如下:
var value1 complex64 value1 = 3.2 + 12i value2 := 3.2 + 12i value3 := complex(3.2, 12) x := real(value1) y := imag(value1)
字符串可以用下表的方式获取其内容,但是字符串在初始化之后,其内容就不能进行修改了。
字符串的遍历,这还跟len()函数作用在字符串上的返回值有关,例子如下:
str := "Hello, 世界" n := len(str) //n = 13 for i:=0, i<n, i++ { fmt.Println(i, str[i]) } for i, ch := range str { fmt.Println(i, ch) } //该段代码输出了9行结果
另外需要注意的,range有两个返回值,第一个是下标,第二个是下标对应的值。
数组在声明了以后,就不能再修改其长度。
数组切片的实质可以理解成3部分:一个指向原数组的指针;数组切片中的元素个数;数组切片已分配的存储空间。
数组切片的声明方式如下:
//基于数组创建数组切片 var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var mySlice []int mySlice = myArray[:] //基于所有数组元素创建切片 mySlice = myArray[:5] //基于数组的前5个(0~4)元素创建切片 mySlice = myArray[5:] //基于数组第5个开始(5~end)的元素创建切片 //直接创建数组切片 mySlice1 := make([]int, 5) //创建一个初始长度为5的数组切片,元素初始值是0 mySlice2 := make([]int, 5, 10) //除以上之外,预留了10个元素的存储空间 mySlice3 := []int{1, 2, 3, 4, 5} //直接创建并初始化一个包含5个元素的数组切片
append函数可以增加切片的元素。注意append函数并不是原地的。其应用例子如下:
mySlice := make([]int, 2, 10) mySlice = append(mySlice, 1) mySlice = append(mySlice, 2, 3) mySlice2 := []int{4, 5} mySlice = append(mySlice, mySlice2...)
注意最后的...,它将mySlice2的元素打散做为append的参数。
也可以通过数组切片来创建切片。例如:
oldSlice := make([]int, 5, 10) newSlice1 := oldSlice[:3] //用oldSlice的前三个元素创建新的切片 newSlice2 := oldSlice[:7] //也可以超出原切片的数量,但是不能超过cap,超出的部分填0
copy函数可以将一个数组切片的内容复制到另一个数组切片。例如:
slice1 := []int{1, 2, 3, 4, 5} slice2 := []int{6, 7, 8} copy(slice2, slice1) //复制slice1的前三个元素到slice2 copy(slice1, slice2) //复制slice2到slice1的前三个位置
map的元素查找可以用以下方法:
myMap := make(map[string]int, 100) //声明一个map,cap为100 value, ok := myMap["1234"] if ok { //找到了 //对value的处理 }
1.4 流程控制
条件语句if的例子如下:
if a < 5 { return 0 } else { return 1 }
需要注意的有:条件语句不需要括号;花括号必须存在;以及最重要的,不允许将最终的return包含在if...else...结构中。
选择语句switch的例子如下:
switch i { case 0: fmt.Println(0) case 1: fmt.Println(1) fallthrough case 3: fmt.Println(3) default: fmt.Println("Default") }
需要注意的有:除非明确的标明fallthrough,否则认为分支默认break;另外,switch后面的条件表达式也可以不设定,这时可以将switch看作是多个if...else...。
循环语句if的例子如下:
for i := 0; i < 10; i++ { fmt.Println(i) } j := 0 for j<10 { fmt.Print(j) j++ } k := 0 for { fmt.Print(k) k++ if k>10 { break } }
总之,Golang是把for和while结合到了一起。同时,也有break和continue。break也可以选择中断哪个循环。
goto就是跳转到label。这个很少用,先写在这里。
1.5 函数
函数的定义和调用:
package mymath import "errors" func Add(a int, b int) (ret int, err error) { if a<0 || b<0 { err = errors.New("Should be non-negative numbers!") return } return a + b, nil } c := mymath.Add(1, 2)
需要注意的有:函数、类型和变量的可见性是由其首字母的大小写来确定的,大写开头的是public,小写开头的是private;函数的返回值的变量名可以先声明出来,在函数体内对变量进行处理后直接return即可;函数可以同时返回多个值。
同时,Golang的函数也支持不定参数,例如:
func myfunc(args ...int) { for _, arg := range args { fmt.Println(arg) } } myfunc(2, 3, 4) myfunc(1, 3, 7, 13) func myfunc2(args ...int) { myfunc(args...) myfunc(args[1:]...) }
通过例子可以看到不定参数的函数的遍历方法和调用方法。以及作为变参函数嵌套的传参方法。我觉得最关键的是记住,...在跟类型一起出现的时候,表明的是变参类型;...在跟变量名一起出现的时候,表明是将该变量内容打散。这种记法与*和&的区别方法一致。
如果希望传递任意类型的不定参数,可以利用interface{}。这里先举一个例子,后面会再具体描述interface{}。
func MyPrintf(args ...interface{}) { for _, arg := range args { switch arg.(type) { case int: fmt.Println(arg, "int") case string: fmt.Println(arg, "string") default: fmt.Println(arg, "unknown") } } }
匿名函数简单的说就是没有函数名的函数。匿名函数可以赋值给一个变量名,也可以直接执行。例如:
f := func(x, y int) int { return x + y } func (ch chan int) { ch <- ACK } (reply_chan)
立即执行的匿名函数,需要把传入的参数放到函数后面的括号中。
这里还有一个闭包的概念,目前还没太懂,待补充。
错误处理,Golang提供了error,defer,panic和recover工具。
error是一个接口,其定义如下:
type error interface { Error() string }
对于需要返回错误的函数,多数情况下定义成下面的形式,并按以下方式调用:
func Foo(param int) (n int, err error) { // ... } n, err := Foo(0) if err != nil { // 错误处理 } else { // 使用返回值n }
那么,对于自定义的error类型(即实现了error接口的类型),通常定义的形式如下:
type PathError struct { Op string Path string Err error } func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() } func Stat (name string) (fi FileInfo, err error) { var stat syscall.Stat_t err =syscall.Stat(name, &stat) if err != nil { return nil, &PathError{"stat", name, err} } return fileInfoFromStat(&stat, name), nil }
defer关键字主要是用来处理代码中需要在最后完成的任务,比如关闭管道,关闭文件等。例子如下:
func CopyFile(dst, src string) (w int64, err error) { srcFile, err := os.Open(src) if err != nil { return } defer srcFile.Close() return io.Copy(dstFile, srcFile) }
另外,如果一个函数中有多个defer关键字,那么它们是以后进先出的方式(即自下而上的)执行。
panic和recover两个函数是Golang中用来处理异常的函数。其流程大致为:当在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程,直至所属的goroutine中所有正在执行的函数被终止。recover()函数用于终止错误流程。一般情况下,recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程,会导致该goroutine所属的进程打印异常信息后直接退出。
常见的recover()调用方法如下:
defer func() { if r := recover(); r != nil { log.Printf("Runtime error caught: %v", r) } }()
这样写,无论函数中是否出发了错误处理流程,该匿名函数都将在函数退出时得到执行。
第一节大概是这样~如果有任何问题还会及时更新~~~
来源:https://www.cnblogs.com/wangzhao765/p/9201252.html