Golang
基本用法
输出
Print 和 Println
参数可以是字符串,数字,数学表达式,传递若干参数用逗号隔开.
1 | package main |
Printf
第一个参数必须是字符串,其中包含格式化动词,如%v
,值由第二个参数决定.
1 | func main() { |
常量和变量
const
声明常量
var
声明变量
1 | var distance = 100 |
自增运算
go 中没有++count
这种,但是有count++
随机数
使用 math 包中的 rand
1 | package main |
Boolean 类型
true 和 false,不会进行类型转换.
字符串
strings.Contains
返回 boolean 类型.
1 | package main |
条件判断
if
注意 if 后不适应()
switch
switch 语句中不需要写 break
switch 后也不需要跟传入参数
循环
for
for 语句后也不用()
,后面的判断如果没有就是无限循环
作用域
变量的作用域在{}
中.
package 作用域
在 main 函数之外声明必须使用 var 声明,不能使用短声明.且作用域存在于 package 中.
短声明
优势:可以在无法使用 var 的地方使用.比如 for 循环中.
1 | var count = 10 |
声明浮点型变量
1 | days := 365.2425 |
只要数字带有小数部分,类型就是float64
.
如果使用整数声明浮点型,必须使用float64
,否则就是整数类型.
单精度浮点类型
go 语言默认是float64
,双精度浮点类型.占用 8 字节内存.
也可以使用float32
,单精度浮点类型,占用 4 字节内存.
使用场景: 处理大量数据时,可以牺牲精度,节省内存.
显示浮点型
使用Print
和Println
打印时,默认显示所有小数.
如果想控制小数显示位数,可以使用Printf
,结合%f
格式化动词.
1 | third := 1.0 / 3 |
浮点型的精度问题
浮点型不适合做金融计算,如果非要使用,可以先乘后除.
1 | third : = 1.0 / 3.0 |
零值
Go 里面每个类型都有一个默认值,即零值.
当声明变量却不初始化时,该值即零值.
1 | var price float64 |
整数类型
int
有符号类型
uint
无符号类型
uint8 表示颜色
可以用来表示 8 位的颜色(红绿蓝 0-255).var red, green, blue uint8 = 0, 141, 213;
uint8 的取值范围正合适,而 int 则多出来几十亿不合适的数.
打印数据类型
在 Printf 中使用%T
.
十六进制
在数值前加0x
即表示十六进制.
打印十六进制
使用Printf
的%x
.
1 | fmt.Printf("%x %x %x", red, green, blue) // 0 8d d5 |
整数环绕
当超出超出整数的取值范围,就会发生整数环绕.
原理: 用二进制表示,比如 11111111,加 1 后变成 100000000,但是内存只有 8 位,所以值变为 0.
1 | var red uint8 = 255 |
打印二进制
格式化动词%b
1 | var green uint8 = 3 |
整数类型的最大值最小值
math 包里,为与架构无关的整数类型,定义了最大值,最小值常量.
1 | math.MaxInt8 |
而 int 和 uint 可能时 32 位或者 64 位,无最大最小值.
避免时间环绕
unix 系统中,时间从 1970 年开始,到 2038 年会超过 20 亿,超过了 int32 的范围.
方法: 使用 int64 或者 uint64.
数值过大
浮点类型数值大但是精度不高,
整数类型精度高但是取值范围小.
采用方法可以
int64 < uint64 < float64 < 使用 big 包
big 包
对于较大的整数(超过 10 的 18 次方): big.Int
对于任意精度的浮点型: big.Float
对于分数: big.Rat
big.Int
使用了big.Int
的等式其他部分也需要使用big.Int
.NewInt()
函数可以把int64
转化成big.Int
类型.
常量和 big.Int 的值不能互换.
字符串
字符串字面值和原始字符串字面值
字符串字面值可以包含转义字符,如\n
.
如果想显示\n
,而不要换行,则可以使用```,即原始字符串字面值
1 | fmt.Println("pece you\nwith") //打印有换行 |
code points, runes, bytes
rune 是 int32 的别名,byte 是 int8 的别名.
自定义类型别名
1 | type byte = uint8 |
可以使用%c
打印该字符.
字符
字符字面量用''
包裹,如果没有指定字符类型,Go 会推断该类型为rune
.
字符字面量也可以用byte
表示.
字符解码
Go 的函数len
可以返回字符的长度,但是有的字符是 16 位或 32 位,那么需要把字符解码成rune
类型,再操作.
使用UTF-8
包,他提供可以按rune
计算字符串长度的方法.RuneCountInString
可以返回转换后的长度.DecodeRuneInString
函数会返回第一个字符,以及字符所占的字节数.
所以 Go 里的函数可以返回多个值.
1 | question := '(*Φ皿Φ*)' |
遍历方法 range
range 返回两个值,一个 i 是索引,c 就是遍历的元素.
1 | func main() { |
类型转换
不同类型不能在一起使用,需要进行类型转换.
数值之间转换
1 | age := 64 |
浮点型转换为整型,小数点后边会被舍弃.
无符号和有符号整数之间也需要进行转换
不同大小的整数类型之间也需要进行转换.
转换时的数据环绕
因为转换时有可能会超过转换类型的最大值,所以可以使用 math 包中的最大值最小值进行判断.
1 | var bh float64 = 32678 |
字符串转换
将rune
,byte
转换成string
,
1 | var pi rune = 960 |
想把数值类型转换成字符串,那么它的值必须可以转换成
code point
.
strconv
包的Itoa
函数可以转换,或者使用Sprintf
strconv
包的Atoi
函数可以转换,且有两个参数,第二个返回错误信息,如果不为空,则有错误.
1 | countdown, err := strconv.Atoi("10") |
函数
- 函数按值传递
- 同一个包中的函数调用彼此不需要加上包名.
函数声明
1 | //rand包的Intl: |
多个返回值
1 | func Atio (s string) (i int, err error) |
可变参数函数
Println
可以接收多个参数.
1 | func Println (a ...interface{}) (n int, err error) |
...
表示函数的参数是可变的- 参数 a 的类型为
interface{}
,是一个空接口. ...
和空接口组合就可以接收任意数量,类型的参数
一等函数(头等函数,高阶函数)
- 可以将函数赋值给变量
- 将函数作为参数传递给函数
- 将函数作为函数的返回类型
闭包和匿名函数
- 匿名函数在 go 中被称为函数字面值,函数字面值需要保留外部作用域的变量引用,所以函数字面值都是闭包的.
- 闭包就是由于匿名函数封闭并包围作用域中 的变量而得名的.
方法
方法也属于函数,只不过函数是独立存在的,方法属于某一个类型,或者与类型有关联.
1 | func (k kelvin) celsius() celsius |
1 | import ( |
方法添加行为
可以将方法中同包中声明的任何类型相关联,但不可以是int
,float64
等预声明的类型进行关联,但是可以通过声明一个新类型的方式曲线救国
1 | func (k kelvin) celsius() celsius |
- 上例中
celsius
方法虽然没有参数,但他前面却有一个类型参数的接收者 - 每个方法可以有多个参数,但只能有一个接收者.
- 在方法中,接收者的行为和其他函数一样
调用方法
变量.方法()
1 | type kevin float64 |
数组
长度len
,声明数组时未被声明的元素的值为零值.
1 | //声明长度为8,元素类型为string的数组 |
数组越界
Go 在检测到对越界元素的访问时会报错
在编译时未发现错误,那么运行时会出现panic
复合字面值初始化数组
可以使用...
作为数组的长度,go 会推断数组长度
1 | var plants := [...]string{ |
遍历数组
for 循环
1 | plants := [...]string{ |
range 循环
类似 map
1 | for i, dwarf := range dwarfs { |
数组的复制
无论是复制给新变量还是传递给函数,都会产生一个新数组的副本.
数组也是一种值,通过值传递来接收参数,所以作为函数的参数很低效.
数组的长度也是数组类型的一部分.
函数一般使用slice
作为参数.