GO语言基础
一、初识Go语言
1、go语言特性
- 垃圾回收:内存自动回收,再也不需要开发人员管理内存,只需要new分配内存,不需要释放
- 天然并发:从语言层面支持并发,非常简单,并且 goroute 轻量级线程,创建成千上万个goroute成为可能
channel:管道,类似unix/linux中的pipe,多个goroute之间通过channel进行通信,支持任何类型
- 多返回值:一个函数返回多个值
2、包的概念
- 和python一样,把相同功能的代码放到一个目录,称之为包
- 包可以被其他包引用
- main包是用来生成可执行文件,每个程序只有一个main包
- 包的主要用途是提高代码的可复用性
示例:
package calc func Add(a int, b int) int { return a + b }
package main import ( "awesomeProject/calc" ) func main() { println(calc.Add(1, 2)) }
二、Go语言基础
1、文件名&关键字&标识符
所有go源码以.go结尾
标识符以字母或下划线开头,大小写敏感
可以用 _ 来接收对象,它是特殊的标识符,用来忽略结果
_ = calc.Add(1, 2)
保留关键字:
break | default | func | interface | select |
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthough | if | range | type |
continue | for | import | return | var |
说明:
- var和const :变量和常量的声明
- var varName type 或者 varName : = value
- package and import: 包和导入
- func: 用于定义函数和方法
- return :用于从函数返回
- defer someCode :在函数退出之前执行
- go : 用于并行
- select 用于选择不同类型的通讯
- interface 用于定义接口
- struct 用于定义抽象数据类型
- chan用于channel通讯
- type用于声明自定义类型
- map用于声明map类型数据
- range用于读取slice、 map、 channel数据
- break、 case、 continue、 for、 fallthrough、 else、 if、 switch、 goto、 default 流程控制
- fallthrough:
1.加了fallthrough后,会直接运行 紧跟的后一个 case或default语句,不论条件是否满足都会执行
2.加了fallthrough语句后, 紧跟的后一个 case条件不能定义常量和变量
3.执行完fallthrough后直接跳到下一个条件语句,本条件执行语句后面的语句不执行
str := "hello world,中国" for i, v := range str { fmt.Printf("index[%d] val[%c]\n", i, v) }
2、Go程序结构
package main import “fmt” func main() { fmt.Println(“hello, world”) }
任何一个代码文件隶属于一个包
import 关键字,引用其他包
golang可执行程序, package main,并且有且只有一个main入口函数
包中函数调用:同一个包中函数,直接调用;不同包中函数,通过 包名.函数名 进行调用
包访问控制规则:大写意味着这个函数/变量是可导出的;小写意味着这个函数/变量是私有的,包外部不能访问
3、常量和变量
常量使用const 修饰,代表永远是只读的,不能修改
const 只能修饰boolean, number(int相关类型、浮点类型、 complex)和string
语法: const identifier [type] = value,其中type可以省略
const b string = “hello world” const b = “hello world”
const ( a = 0 b = 1 c = 2 )
const ( a = iota//0 b //1 c //2 )
变量定义语法: var identifier type
在函数内部,可以使用更简略的 := 方式声明并初始化变量,但是不能用于全局变量声明
var a string="hello" var( b int //默认为0 c string//默认为"" d bool //默认为false )
在函数内部声明的变量叫做局部变量,生命周期仅限于函数内部
在函数外部声明的变量叫做全局变量,生命周期作用于整个包,如果是大写的,则作用于整个程序。
4、数据类型和操作符
基本概念
Go 是强类型语言,因此不会进行隐式转换,任何不同类型之间的转换都必须显式说明
Go 不存在像 Cpp 那样的运算符重载,表达式的解析顺序是从左至右
Go 对于值之间的比较有非常严格的限制,只有两个类型相同的值才可以进行比较,如果值的类型是接口,它们也必须都实现了相同的接口。如果其中一个值是常量,那么另外一个值的类型必须和该常量类型相兼容的。如果以上条件都不满足,则其中一个值的类型必须在被转换为和另外一个值的类型相同之后才可以进行比较。
bool类型
只能存true和false
int类型
Go 也有基于架构的类型,例如:int
、uint
和 uintptr
。
这些类型的长度都是根据运行程序所在的操作系统类型所决定的:
int
和uint
在 32 位操作系统上,它们均使用 32 位(4 个字节),在 64 位操作系统上,它们均使用 64 位(8 个字节)。uintptr
的长度被设定为足够存放一个指针即可。
Go 中不允许不同类型之间的混合使用,但是对于常量的类型限制非常少,因此允许常量之间的混合使用
func main() { var a int var b int32 a = 15 //b = a + a // 编译错误 b = int32(a + a) // 编译ok b = b + 5 // 因为 5 是常量,所以可以通过编译 }
注:如果你实际存的数字超出你要转换到的类型的取值范围的话,则会引发 panic
float类型
Go 语言中没有 float 类型。(Go语言中只有 float32
和 float64
)没有 double 类型。
float32
精确到小数点后 7 位,float64
精确到小数点后 15 位。由于精确度的缘故,你在使用 ==
或者 !=
来比较浮点数时应当非常小心。你最好在正式使用前测试对于精确度要求较高的运算。
尽可能地使用 float64
,因为 math
包中所有有关数学运算的函数都会要求接收这个类型。
通过增加前缀 0 来表示 8 进制数(如:077),增加前缀 0x 来表示 16 进制数(如:0xFF
),以及使用 e
来表示 10 的连乘(如: 1e3 = 1000,或者 6.022e23 = 6.022 x 1e23)
格式化输出
在格式化输出时,可以使用 %t
来表示你要输出的值为布尔型
在格式化字符串里,%d
用于格式化整数(%x
和 %X
用于格式化 16 进制表示的数字),%g
用于格式化浮点型(%f
输出浮点数,%e
输出科学计数表示法),%0nd
用于规定输出长度为 n 的整数,其中开头的数字 0 是必须的,%n.mg
用于表示数字 n 并精确到小数点后 m 位
%b
是用于表示位的格式化标识符
字符类型
字符只是整数的特殊用例,byte
类型是 uint8
的别名
var ch byte = 'A' 或 var ch byte = 65 或 var ch byte = '\x41'
字符串类型
字符串是字节的定长数组
字符串表示方式:
var str = "hello world"
和 C/C++不一样,Go 中的字符串是根据长度限定,而非特殊字符 \0
注:获取字符串中某个字节的地址的行为是非法的,例如:&str[i]
二元运算符
按位与 &
:同为1相&结果为1
按位或 |
:有一个为1结果为1
按位异或 ^
:相异为1
位清除 &^
:将指定位置上的值设置为 0
在 Go 语言中,&&
和 ||
是具有快捷性质的运算符,当运算符左边表达式的值已经能够决定整个表达式的值的时候(&&
左边的值为 false
,||
左边的值为 true
),运算符右边的表达式将不会被执行。
其他
逻辑运算符:==
、!=
、<
、<=
、>
、>=
数学操作符: +、 -、 *、 /
类型转换, type(variable), 比如: var a int=8; var b int32=int32(a)
5、值类型和引用类型
值类型:变量直接存储值,内存通常在栈中分配
引用类型:变量存储的是一个地址,这个地址存储最终的值,内存通常在堆上分配,通过GC回收
值类型:基本数据类型int、 float、 bool、 string以及数组和struct
引用类型:指针、 slice、 map、 chan等都是引用类型
三、Go函数
函数声明: func 函数名字 (参数列表) (返回值列表) {}
func Add(a int, b int) int { return a + b }
函数特点:
a. 不支持重载,一个包不能有两个名字一样的函数
b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
c. 多返回值
函数参数传递方式:值传递;引用传递
注:值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效
函数参数传递方式: 值传递;引用传递
注:map、 slice、 chan、指针、 interface默认以引用的方式传递
命名返回值的名字:return自动匹配返回对象的名字
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return }
_ 标识符,用来忽略返回值:
func main() { sum, _ := calc(100, 200) }
可变参数:
func add(arg…int) int { }//0个或多个参数 func add(a int, arg…int) int { }//1个或多个参数
注:其中arg是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数
defer用途:
当函数返回时,执行defer语句,因此可以用来做资源清理(文件,数据库,锁资源等)
多个defer语句,按先进后出的方式执行
defer语句中的变量,在defer声明时就决定了