on
Go语言学习笔记
最近零星地看了些go语言的语法,起初看的是《Go语言编程》,不推荐,结构不清晰,讲述的很粗糙且口语化。后来看了《Go语言实战》,比七牛云那本读起来舒服很多,尤其对我这种入门级选手而言。还有一本《Go程序设计语言》在路上,期待能带来更详实的解读。
以下是学习总结的简单笔记,仅供自己入门回顾。
Go是静态编译型语言,静态
是指编译时就可确定变量类型,编译型
是相对于脚本语言的解释器而言。
开发工具
- GoLand By Jetbrains。
- Sublime text 3 + gosublime插件
go CLI
- go build:编译
- go clean:删除编译生成的可执行文件
- go get:下载和安装包/依赖
- go run:编译并运行
变量
变量的声明:var a int
,多个同类型的变量声明var a, b int
。GO语言中声明时类型在变量名之后。声明后的变量为零值。
变量的赋值:value := 10
或var value int = 10
或var value = 10
,编译器会进行类型推导
常量:const a = 9
,常量的赋值是编译期行为。
类型
以下为基础类型,尤其要注意字符串和错误类型都是内置的基础类型。
- 布尔型:bool
- 数值类型
- 整型:int8, byte, int16, int, uint, uintptr。一般使用int/unit,平台相关,取决于平台64/32位。
- 浮点数:float64, …
- 复数:complext64, complex128
- 字符串:string
- 字符:rune
- 错误类型:error
复合类型
- 指针
- 数组
- 切片
- map
- 通道 chan
- 结构体 struct
- 接口 interface
和Java很明显的不同之一是,在GO中,string为基础类型,且map属于内置类型,无需标准库的引入。另外,Go是支持指针的,这点很重要,因为很多设计上都是传拷贝。
引用类型(vs值类型):
- 切片
- map
- 通道 chan
- 接口 interface
-
函数 func
- 数组,是值类型。所有的值类型变量在赋值和作为参数传递时都是传值的拷贝。故作为参数传递时,整个数组会被拷贝,若数组很长则很占用内存。
arr := [5]int{1,2,3,4,5}
- 切片。是引用类型。包含:指向原生数组的指针、切片中的元素个数、切片分配的存储空间(最大元素个数)。
s := []int{1,2,3}
,和数组初始化的区别在于,不指定方括号中的元素个数则为切片。 - map。声明
var m map[string] int
,创建myMap := make(map[string] int)
流程控制
- if else语句:可以不加括号。
- switch语句:无需用break来明确跳出一个case
- for循环:for三段式循环
for i:=1; i<10; i++{
,for模拟while循环for{
- goto语句:很少用。
函数
func addOrMinus(a int, b int) (int, int) {
用func
关键字定义函数,后面跟函数名,函数名中第一个括号为参数及其类型,第二个括号为返回值类型。支持无返回值/多返回值。- 不定参数
func addNums(nums ...int) {
,...type
本质上是一个数组切片,即[]type
- 任意类型的参数
interfae{}
,任意类型都认为是实现了空接口
,所以空接口参数类型可表示任意类型。
struct结构类型
新类型的定义:
type Person struct {
name string
sex bool
}
新类型的初始化:p := new(Person)
或p := Person{'wanghan', false}
方法
方法的定义,需要在函数的func
关键字和函数名之间,加入接收者:
func (p Person) changeName(name) {
p.name = name
}
接收者有值接收者和指针接收者两种类型。上面例子为值接收者,下面例子为指针接收者:
func (p *Person) changeName(name) {
p.name = name
}
区别在于,是传结构体的拷贝/引用。我的理解是,当结构体中有类似slice的引用类型时,即使是传拷贝,此引用类型的字段也是传的引用。
一般来说,优先使用指针接收者,好处在于:1.避免结构体拷贝,省内存 2.可改变结构体内容(如果有需要)
接口
- 接口的实现无需与接口显式关联,只要实现了接口中定义的方法,则认为实现了该接口。与JAVA相比,非侵入性。
- 接口的实现分为:值接收者实现的接口/指针接收者实现的接口
- 值接收者实现的接口,可被值/指针调用。指针接收者实现的接口,只能被指针调用。由
go语言规范定义的方法集规则
决定。
组合代替继承
- 标识符提升 + 接口提升(外部也实现接口时则不提升)
并发
goroutine <-> 逻辑处理器 <-> 线程 <-> 物理处理器
goroutine和线程的区别:
- 协程由用户态实现
- 非抢占式调度,而是主动出让
一个线程上有多个协程?那么显然就不是真正意义上的并发了。
- 锁与通道。在GO中也可以像在JAVA中那样使用锁(传统同步机制)进行同步,有原子函数和互斥锁mutext;更推荐且更优雅的方法是使用通道。
- 通道:无缓冲、有缓冲(类似队列?)
- 个人感觉通道的使用和JAVA中signal/notify类似,以及是通道有类似volatile的特性保证变量的可见性。