文章目录
包和Go工具
形如package main
的语句表示声明本代码属于哪个包(类似库和模块),Go中的包以目录形式组织,同一目录下的Go源文件属于一个包,目录名称即包名,特殊的包名main
和一些测试包
一个Go文件中依赖一些别的包,那么就需要导入import (pkgpath)
,其中路径可以简写为最后一个目录名称
Go WorkSpace
GOPATH
指定工作目录的一个环境变量
export GOPATH=
工作目录下包括三个子目录src
、bin
、pkg
,分别对应源文件、二进制、包
GOROOT
指定Go安装目录和标准库安装位置
GO env
查看Go命令的环境变量
go get
安装单一包或者用...
下载整个子目录的每个包
go build
进行编译,保留最后的可执行文件在当前目录下,并且Go支持交叉编译
// +build linux darwin //表示仅在对应的系统下进行编译该包
// +build ignore //表示不编译本包
go install
保留中间代码的编译
go doc
查看包文档
go list
查询可用包的信息
…
定义对象和输出
Go中的标识符首字母大写表示导出,即对外部包可见,当然这是对于全局变量来说
四种定义关键字
var
、func
、type
、const
,分别定义变量、函数方法接口、声明类型、常量
定义变量
Go的变量的数据类型强制在标识符之后,每个变量标识符之间以,
分隔,如果多个同类型变量可以只在最后一个变量后跟数据类型,Go中的变量会有默认初始化,为对应类型意义上空值,定义变量分为完整定义和简短定义,使用简短定义时必须至少新产生一个对象,也就是说除此之外的变量可以被视作赋值操作
var Name typeA //完整定义
Name := value //简短定义
定义函数方法接口
func FunctionName(args_list)(returnlsit) {
}//函数
func InterfaceName interface{
}//接口
func (t T) MethodName(argslist)(returnlist){
}//方法
定义声明类型
Go中经过type
后的声明类型以声明类型为准,即使底层类型相同,也会被视作不同的类型,并且Go的方法不能绑定到基础类型,对于基础类型,需要type
后才能被方法绑定
type Newname basetype
type Newname struct {
}
定义常量
Go常量只需要const
声明即可
const p = initvalue
基本输出语句
import "fmt"
fmt.Println()
fmt.Printf()
基本数据类型
整形
Go中整形全部以intX
表示,X表示bit
位数,可以取0、8、16、32、64,对于想表示无符号整形,在前面加u
,如uint32
,当X取0的时候int
默认表示int32
uintptr
可以表示指针
为了强调数据存储的内容,在表示字符的时候,对int8
和int32
改用byte
和rune
(和汇编一样)类型,分别存储字节和Unicode
编码
boolean
Go中的bool
和int
不会隐式转换,也就是说对于if
等判断语句必须比较bool
值
字符串
内置len()
返回长度,支持字符串+
…
基本数据结构
数组
当使用简短初始化的时候arr :=[n]int{..}
的时候必须在[]
中指名n
或使用[...]
,否则变量会被推断成切片,除此之外数组的指定index
初始化方法[...]int{index:value}
这里的:
不是表示切片的意思
切片
一个很小的类,指向底层数组,使用切片的时候区间表示前闭后开
在一些情况下,可以申请一个空Slice
用于处理数据
Map
Go中没有set
,需要通过Map[key]bool
实现,或者是采用bitmap
的方式,查询Map中的key-value时采取range
关键字,使用ok
接收第二返回值,判断否存在键
结构体
匿名嵌入
Go支持在结构体中匿名嵌入,并且可以层级嵌套,这样做的目的是为了写法上的简化,因此对于一种类型的匿名嵌入,只能至多存在一个
结构体可比当且仅当结构体的每个成员可比,并且只支持判等和不等
方法
Go的方法是绑定到具体类型的函数,拥有有该类型的对象可以使用此方法
方法声明
形如func (t type) Method(args)(return_list){}
或者func (t *type)...
,其中type
不允许是指针和接口,不允许是基本类型必须是经过type
重新定义过的类型(底层类型可以是基本类型,如map
、slice
),值得一提的是,对于绑定到t *type
的方法,允许实际接收对象的值为nil
,进行调用,在实际意义上可以将值为nil
理解为一些空数据结构如空链表空map
其中,Go编译器对于左值变量,允许方法在取址和解引用上简化书写,因为编译器可以获取它的地址
func (t *type1) Method()(){
}
func (t type1) Method2()(){
}
var p type1
q := &p
//(&p).Method 等同与p.Method
//q.Method2 等同于 (*q).Method2
Go不允许函数重载,即指的是在一个命名类型空间中,不允许函数名相同(Go中考虑函数名而不是函数签名)
内嵌类型
内嵌类型有匿名和非匿名的内嵌两种
对于匿名内嵌类型,对于一种命名类型最多只能存在一个匿名内嵌,但是允许同时存在相同类型的匿名和非匿名
type in int
type out struct {
in
fst in
snd int
}
对于方法,外部类可以作为内嵌匿名对象的方法的实际接收者,但是不能作为函数的参数,也就是说Go没有继承的概念
type T int
type out struct {
T
fst int
}
func (t T) Say(arg1 T)(){fmt.Println("This is T say")}
func main(){
var cse out
cse.Say(cse.T) //cse是外部类,但因为内嵌T,可以作为T的方法的接收者,但参数不行,必须显式指出传递的是cse.T成员
}
多层匿名嵌套可以带来调用上的简化
方法表达式
选择器
形如p.Method
(不加()
运算符)的表达式,叫做选择器,表达式返回将方法绑定到p
的函数(似乎将p
作为新函数的第一参数),因此可以选择一个变量来接收该函数,或者是转发函数的时候使用选择器形式简写
q := p.Method
q(args)//等于p.Method(args)
函数
Go中的函数是第一类对象,可以被当作参数传递
wiki定义
第一类对象(英语:First-class object)在计算机科学中指可以在执行期创造并作为参数传递给其他函数或存入一个变数的实体[1]。将一个实体变为第一类对象的过程叫做“物件化”(Reification)[2]。
因为是第一类对象,所以可以定义一个函数类型的变量,函数类型变量之间不可以比,只能与nil
比较
匿名函数
Go支持闭包,这部分底层原理不太懂,简单说可以保存函数的执行环境信息,进行传递
可变参数
使用...typeA
的语法,...
范围内的所有参数必须是typeA
类型,遍历使用range
defer
Go关键字,使后跟的函数推迟到代码块的函数结束的时候执行,多个derer
以FILO
的顺序执行
接口
Go中的方法需要绑定到类上,有些时候,为了隐藏类的内部信息,我们需要一种抽象类,抽象类的内部成员只有绑定到该抽象类的的方法的函数原型,这就是接口interface
,因此对于绑定到抽象类的方法,必须定义在type interface
中,因此禁止t type
定义方法的方式中的type
为interface
从另一个角度理解接口抽象类,如果我们有更高级别的对对象的概括,那么就可以在程序的逻辑和存储上组织这些底层类型不同的对象,这是很方便的
接口定义
形如
type Name interface {
Method1(args)(return list)
...
}
Name
称为接口类,该类是抽象类,当某个类实现了Name
中给出的所有方法,则该类也是Name
抽象类
同时,接口也可以像结构体一样,进行内部嵌套(包含内部接口类)
注意,在方法中存在调用t type
和t *type
两种情况方法的语法糖(编译器会自动处理接引用和取址),但是对于该方法而言,实际上定义的接收类型是什么,那就是什么,也就是说只有对应的接收类型的类才算实现了interface
中定义的方法
空接口
接口值
对于接口类的实例,存储了T
和V
两个指针,其中T
表示的是类型描述符指针,表示该对象绑定到哪个底层类上,V
是动态值指针,指向底层类实例值
type P interface{
...}
type T struct {
}
var i P
i := T
接口对象之间是可比的当且仅当其类型描述符相同和底层类可比(各个成员可比,且仅限==
和!=
),否则不可比,如果对不可比对象进行比较,会产生panic
调用空接口上的方法会产生panic
Sort.Interface
package sort
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int) //i,j are indeies of seq
}
Len
排序序列的长度,Less
比较的方法,Swap
交换次序的具体实现
sort.Reverse()
内置反转序列的函数
error
type error interface {
Error() string
}
断言
Go的断言表达式操作在接口对象上,检查接口值是否为nil
并且其动态类型是否是是断言类型
ssa包中的TypeAssert
不理解ssa
,仅先记录下
package ssa
//Go文档中关于ssa包的节选描述
//The level of abstraction of the SSA form is intentionally close to the source language //to facilitate construction of source analysis tools. It is not intended for machine //code generation.
type TypeAssert struct {
X Value //接口值中的动态类型
Assertedtype types.Type //断言的类型
CommaOk bool //断言成功与否的布尔值
}
断言表达式
形如x.(T)
,表示对接口对象x
的动态类型,进行T
类型的断言,如果T
是具体类型(非抽象类即接口),则检查x
的动态类型符号是否指向T
,成功表达式返回x
的动态值,失败则panic
,如果T
是接口类型,检查x
的动态类型是否实现了T
接口的所有方法,成功返回x
的接口值,失败panic
,如果采用value-ok
的形式,还需要接收CommaOk
,并且可以规避panic
Go文档中关于断言类型T为interface的描述
If AssertedType is an interface, TypeAssert checks whether the dynamic type of the interface is assignable to it, and if so, the result of the conversion is a copy of the interface value X. If AssertedType is a superinterface of X.Type(), the operation will fail iff the operand is nil. (Contrast with ChangeInterface, which performs no nil-check.)
疑问
断言的语法是语法糖吗?Go内部是怎么处理断言的呢?