小编商学院毕业误打误撞进入区块链这个新领域,本着既来之则安之的心态想着在这个领域继续待下去,为了未来职业生涯的可持续发展,小便开始接触编程知识,鉴于大部分区块链代码是go语言编写,所以尝试开始学习go语言,整理了一下学习笔记。
包、标量和函数
打印的概念:
Println : 换行打印;打印的内容中如果含有一句话,加双引号后表示字符串。
例子:fmt.Println("My favorite number is", rand.Intn(10))
Printf : Printf打印的内容中有%号,表示格式化打印,格式化打印但是不换行,后面加\n后表示换行打印;
%v : 打印值;%T:打印格式;%d: 十进制整数(int);%g:按照浮点数格式打印,不打印无意义的数;s%:。
例子:fmt.Printf ("Now you have %g problems.", math.Nextafter(2, 3)
Println 和Printf 后面的大括号中,要跟一个包中的一个函数及传入的参数,表示要调用该包中的该函数,函数名的首字母要大写。(Go中,首字母大写的名称是被导出的)
例子,
如上例子中的math.Nextafter(2, 3),math是包,Nextafter是函数名,且首字母大写。
Fprint,向指定目标中来打印
函数可以接收多个或是单个参数,接收多个参数时,再()中用逗号隔开。参数的类型再参数名后面。
参数后面时返回值,返回值后的{}中是函数体,函数体中含有要返回的值
return后面加要返回的值及其类型;
返回值可以有多个;
可以对返回值进行命名(写在return语句的前面);
没有参数的返回语句,返回当前的值,即直接返回。
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
变量的定义使用var或是 := ,var既可以定义在包等次,也可以定义在函数层次。常量用const来定义。
函数外的每个语句都必须以关键字开始(`var`、`func`等),`:=` 结构不能使用在函数外。
rune 是 int32 的别名。
类型转换,表达式 T(v) 将值 v 转换为类型 `T`
流程控制语句
for语句
Go语言中只有一个循环结构-for循环;
for 是 Go 的 “while”,因此在前后语句为空时,可以省略条件语句前后的分号;
i++是一个语句,它相当于add 1 to i ;相当于i += 1 ;相当于 i = i + 1
字符串要加双引号“”
Sqrt是开方的含义
pow(3,3)是求幂的意思
printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。
printf()函数的调用格式为: printf("<格式化字符串>", <参量表>)。
switch语句
选择语句 switch case,根据传入条件的不同,选择语句会执行不同的语句。
复杂类型
指针:
*T 是指向类型 T 的值的指针,指针保存了变量的内存地址,;
*加在类型的前面,表示的是一种指针类型。用于表示这个指针的类型是什么。
例子:*int
var p *int表示“定义一个P,P是一个整数的指针”
&符号会生成一个指向其作用对象的指针
例子:p = &i 表示“给P赋值,p是保存了i的内存地址的指针”
fmt.Println(*p) // *p通过p这个指针来读取p这个内存地址对应的数值i;
*p = 21 // 通过指针 p 设置 i;
内存是有编号的,每个数字对应一个存储单位,一个单位对应一个字节(byte),bit指的是逻辑位。一个byte对应8个bit.
&表示 取地址,&加在变量前是取变量的地址,*加在变量前是根据变量的值作为地址去找对应的变量。
结构体:
一个结构体(`struct`)就是一个字段的集合(此处可以理解为,定义一个struct相当于定义一个Excel表格,表格用来描述结构体对象的所有属性)
定义了一个结构体后,所有实现了结构体格式的字段,都可看作实现了这个结构体的功能。
结构体字段使用点号来访问;
结构体中,有初始化时需要有等号=
结构体中,多个初始化之间用逗号,
v.X 表示要取 v中的X元素
例子:
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
结构体的字段也可以通过结构体指针来访问;
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
数组和Slice
Slice、map、指针都是由make函数构造的。
例子:a := make([ ]int, 5)——通过make函数构造了一个切片a,其长度是5
其中make可以传第三个参数,表示切片的容量cap
一个 nil 的 slice 的长度和容量是 0
例子:b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
可以通过append函数slice中添加元素,func append(s []T, vs ...T) [ ]T
例子:var a [ ]int 定义了一个切片a,该切片len和cap都是0;
a = append(a, 0) 通过append函数将0添加到了切片a中,现在切片a的len=1,cap=1
Range 是遍历,i是索引,v切片中的值;
<<代表的是左移;
Slice[i] = ”A”,表示将切片的第i个值赋值为字符串A
map
map 是通过 key 来快速检索value的映射; key类似于索引,指向数据的值;
例子:var m map[string]Vertex 中[string]表示map中的key值,该key值是一个字符串类型的值;
[ ]后面的Vertex是key值对应的value;
例子:map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967}
可以在语法的元素中省略键名。
例子:
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
修改map
在map m中插入或是修改一对“key-value”: m[key]=elem;
从map中根据value读取key:elem=m[key],当不存在这个key时,结果是key对应value类型的零值;
删除“key-value”: delete(m, key);
通过双赋值(一个value+一个ok)检测某个key是否存在:elem, ok = m[key];
如果 key 在 m 中,`ok` 为 true 。否则, ok 为 `false`,并且 elem 是 map 的value类型的零值。
函数的闭包:函数adder的返回值是一个函数,该函数没有函数名,是一个匿名函数;该函数的目的是在闭包中递增x变量。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
例子:
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x //sum += x表示:sum=sum+x
return sum
}
}
在Go语言中,函数的上下位置没有关系,上面一个函数的变量可以在下面函数中来定义,程序是在整个程序中来寻找这个变量的定义的。但是C语言中,变量的位置是有影响的。
方法和接口
方法
Type都是定义类型的,可以定义类型,变量的类型、结构体的类型,接口的类型。
Go语言中,可以在结构体中定义方法。接收者在func 关键字和方法名之间;
接收者是我们定义的行为的指向对象;
例子:
type Vertex struct {
X, Y float64
}
//v是接收者,*Vertex表示是v是一个Vertex
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
可以对包中的任意类型定义任意方法,而不仅仅是针对结构体,即接收者的不仅可以是指针类型的,也可以是其他类型的,例如浮点数等等。
接口
接口类型是由一组方法定义的集合;
接口是为类型服务的,说明某个类型是否具备某个接口(某些特定方法),所以接口后面的花括号中不是函数,而是方法;
例子:
type Person interface {
Height() float64
}
//接口是方法的集合,所以接口后的花括号中是方法,此处可以有多个方法,这些方法都是自己定义的,不写接收者,也不写func; 这些方法描述了Abser的各个属性,后面具备所有属性的结构体都可以看作是Abser.
Go语言中的接口都是隐式接口,隐式接口解藕了实现接口的包和定义接口的包:互不依赖
Stringers
Stringer 是一个可以用字符串描述自己的类型,该接口用于输出自己的类型。
错误
//当一个函数被调用时,可能会因为很多原因不能正确的执行,这时候会返回一个错误的状态,error接口,就是用来函数是不是被正确的调用执行,如果被正确调用执行则error为nil,如果没有被正确的调用执行,则error非nil;
Go 程序使用 error 值来表示错误状态;
通常函数会返回一个 error 值,调用的它的代码应当判断这个错误是否等于 `nil`, 来进行错误处理;
error 为 nil 时表示成功;非 nil 的 error 表示错误。
Readers
io 包指定了 io.Reader 接口,它表示从数据流结尾读取;
函数后面一定会跟一个(),没有括号的是可能是变量;
一个变量后面跟一个点(.),再跟一个函数调用,表示的是这个变量的方法的调用;
例子:r.Read(b)
如果,一个变量后面跟一个点(.),再跟一个变量名,表示这个变量中的一个元素;
例子:r.Read //表示r中的Read元素
切片变量的值就是他的地址。(Map变量中也是这样)
例子:b := make([ ]byte, 8),b就是切片的地址。
Web服务器
包 http 通过任何实现了 http.Handler 的值来响应 HTTP 请求;
Handler也是一种接口类型;
图片
Image也是一个接口,在Package.Image中定义;
Image后的花括号中,跟的是一个或是多个方法或是方法;
并发
goroutine
goroutine 是由Go运行时环境管理的轻量级线程。
channel
channel 操作符: <- (箭头“就是数据流的方向)
ch <- v // 将 v 送入 channel ch;
v := <-ch // 从 ch 接收,并且赋值给 v;
channel使用前必须要用make创建
缓冲channel
为 make 提供第二个参数作为缓冲长度来初始化一个缓冲 channel:
ch := make(chan int, 100)
//100为channel的缓冲数,表明channel中数字大于100时才会堵塞
range 和 close
只有发送者才能关闭 channel,而不是接收者。向一个已经关闭的 channel 发送数据会引起 panic。
只有在需要告诉接收者没有更多的数据的时候才有必要进行关闭,例如中断一个 `range`
select
select中有很多case,channel可以选择某一个case进行数据的传送,只有当所有case都不能执行时,才会阻塞。
例子:
select {
case i := <-c:
// 使用 i
default:
// 从 c 读取会阻塞
}
默认选择
当 select 中的其他条件分支都没有准备好的时候,`default` 分支会被执行