类型划分
go语言的数据类型大致分为四大类:基础类型,聚合类型,引用类型,接口类型
- 基础类型:数字,字符串,布尔
- 聚合类型:数组,结构
- 引用类型:指针,切片,map,函数,通道
- 接口类型:接口
数字
整数
- 有符号整数:int8,int16,int32,int64
- 无符号整数:uint8,uint16,uint32,uint64
- 特定类型:int,uint表示平台上运算效率最高的值
- 特殊类型
- rune:用于指定值的Unicode码点,与int32类似
- uintptr:数据底层存放指针
- 范围:有符号整数是0~2^(n-1),无符号整数 -2^(n-1) ~ 2^(n-1)-1,n是位数
注意:go语言是强类型语言,具有明确的类型定义,类型与类型之间(例如:int32 与 int64)要进行强制类型转换才可相互使用
浮点数
golang支持两种大小范围的浮点数,float32 和float64
- float32
- 支持6位有效数字(精确位数,超出范围后,会有误差)
- 最大值为3.4e38,可以用math包中的math.MaxFloat32表示
- float64
- 最大值为1.8e308,math.MaxFolat64表示
- 支持15位有效数字(精确位数,超出范围后,会有误差)
注意点
大多数情况下,使用浮点数,推荐用float64,对应的float32可以表示的范围相对较小,精确范围相对较小,容易产生误差
运算符与math
整数独有的运算符,取模%,其他运算符是数字类型通用的,稍后会提及
- %:取模又称取余运算符,go语言有自己的特异性,取模余数的正负号和被除数一致,例如:-5%3 = -2 ,-5%-3=-2
一级: * / % << >> & &^
二级:+ - | ^
三级:== != < <= > >=
四级:&&
五级:||
运算优先级:一级最高,五级最低,依次类推
func main() {
fmt.Printf("-10 Abs is %v \n", math.Abs(float64(-10))) //取到绝对值
fmt.Printf("3.14 Ceil is %v \n", math.Ceil(3.14)) //向上取整
fmt.Printf("3.14 Floor is %v \n", math.Floor(3.14)) //向下取整
fmt.Printf("10 and 3 Mod is %v \n", math.Mod(10, 3)) //取余数 10%3 效果一样
fmt.Println(math.Modf(3.14)) //取整数跟小数
fmt.Printf("2 and 2 Pow is %v \n", math.Pow(2, 2)) //X 的 Y次方 乘方
fmt.Printf("10 and 2 Pow10 is %v \n", math.Pow10(2)) //10的N次方 乘方
fmt.Printf("Pi is %v \n", math.Pi) //π
fmt.Printf("3.14 Round is %v \n", math.Round(3.14)) //四舍五入
fmt.Printf("3.14 IsNaN is %v \n", math.IsNaN(3.14)) // 判断参数是否表示一个NaN(Not A Number)值。
fmt.Printf("3.14 Trunc is %v \n", math.Trunc(3.14)) // 返回整数部分(的浮点值)。
fmt.Printf("3.14 Max is %v \n", math.Max(-3.14, 0)) // 返回x和y中最大值
fmt.Printf("3.14 Min is %v \n", math.Min(-3.14, 0)) // 返回x和y中最小值
fmt.Printf("10 and 9 Dim is %v \n", math.Dim(10, 9)) // 函数返回x-y和0中的最大值
fmt.Printf("10 and 9 Dim is %v \n", math.Dim(10, 9)) // 函数返回x-y和0中的最大值
fmt.Printf("2 and 3 Pow is %v \n", math.Pow(2, 3)) // 返回x^y
}
out
-10 Abs is 10
3.14 Ceil is 4
3.14 Floor is 3
10 and 3 Mod is 1
3 0.14000000000000012
2 and 2 Pow is 4
10 and 2 Pow10 is 100
Pi is 3.141592653589793
3.14 Round is 3
3.14 IsNaN is false
3.14 Trunc is 3
3.14 Max is 0
3.14 Min is -3.14
10 and 9 Dim is 1
10 and 9 Dim is 1
2 and 3 Pow is 8
复数
golang中复数也分为两种,complex64,complex128
- 内置complex函数:两个参数,实部和虚部
- 内置real函数:取实部
- 内置imag函数:取虚部
func main() {
num := complex(1, 2)
fmt.Printf(" num is %v,real is %v, imag is %v ", num, real(num), imag(num))
}
out
num is (1+2i),real is 1, imag is 2
布尔
bool类型位真假值,只有两种可能,true,false通常用于if和for循环判断条件,可以和and(&&)or(||)进行组合运算
短路行为:布尔值和&&或者||组合运算时,左边操作符可以确定结果,则不会进行右边的预算
func main() {
// 借助参考书的demo
// str := "str"
str := ""
if str != "" && str[0] == 's' {
// str是"" 则 str != “” 是false
// 因为用到了&&,所以整个表达式的结果已经确定是false
// 因此后面的 str[0] 条件被短路了,不做验证
fmt.Println(" str first is s ")
} else {
// 根据以上描述,理应走到此逻辑
fmt.Println(" str first not is s ")
}
}
字符串
基础定义
定义:不可变的字节序列
特点:
- 不可更改,强改报错
- 子字符串可以和父级字符串安全的公用同一段底层内存,arr与subArr底层字节数组是同一个
- 子字符串的开销低廉
func main() {
str := "hello world"
//str[0] = 'H'// 编译报错,无法修改字符串
str1 := str[0:6]
str2 := str[2:]
fmt.Println(str1)
fmt.Println(str2)
}
out
hello
llo world
字面量
-
字面量声明
常规字面量,可以有转移符
str := "hello world " -
原生字面量
由反引号构成,可以换行书写,转移符会失效
因为可以换行书写,所以回车符会被删掉
func main() {
str := "hello world \n hello golang "
fmt.Println(str)
fmt.Println("=============================")
str2 := `hello world \n hello golang
str 回车`
fmt.Println(str2)
}
out
hello world
hello golang
=============================
hello world \n hello golang
str 回车
字符串与slice
- 常用的四个标准包
- bytes:用于操作字节slice([]byte)
- strings:提供字符串的搜索,替换,比较,切割等等
- strconv:类型转换,用于转换布尔值,证书,浮点数
- unicode:类型判断,用于判断指定参数是否为指定类型,返回bool值
// 这里以strings 举例,其他包直接点进去可以看到对应的api
func main() {
str := "hello world"
// 搜索
isHas := strings.Contains(str, "hello")
isStart := strings.HasPrefix(str, "hello")
isEnd := strings.HasSuffix(str, "world")
index := strings.Index(str, "l")
count := strings.Count(str, "l")
// 拼接
arr := []string{"A", "B", "C"}
str0 := strings.Join(arr, ",")
// 替换
str1 := "Hello World"
// 最后一个参数表示替换次数,如果是0表示,全局替换
str2 := strings.Replace(str1, "l", "L", 1)
// 切割
// Fields 是根据空格来切割
// Split 是根据指定字符串切割
str3 := "Hello, golang, hello,java"
field := strings.Fields(str3)
split := strings.Split(str3, ",")
fmt.Printf(" hello world has hello is %v \n", isHas)
fmt.Printf(" hello world start by hello is %v \n", isStart)
fmt.Printf(" hello world end by world is %v \n", isEnd)
fmt.Printf(" join A,B,C is %v \n", strings.Join(arr, ","))
fmt.Printf(" index is %v \n", index)
fmt.Printf(" l count is %v \n", count)
fmt.Printf(" join str is %v \n", str0)
fmt.Printf(" replace str2 is %v \n", str2)
fmt.Printf(" Fields value is %v\n", field)
fmt.Printf(" Split value is %v\n", split)
}
out
hello world has hello is true
hello world start by hello is true
hello world end by world is true
join A,B,C is A,B,C
index is 2
l count is 3
join str is A,B,C
replace str2 is HeLlo World
Fields value is [Hello, golang, hello,java]
Split value is [Hello golang hello java]
- 字符串拼接
常规累加方式拼接会多次分配内存和多次数据复制,在出现需要频繁的字符串拼接情况先,建议使用buffer.Builder,官方建议,避免了多次内存的分配
func main() {
var build strings.Builder
t1 := time.Now()
for i := 0; i < 1000; i++ {
for i := 0; i < 100; i++ {
build.WriteString("a")
}
}
t2 := time.Now()
// 这里为验证准确,再转换再计算时间
str := build.String()
fmt.Println(t2.Sub(t1))
str2 := ""
t3 := time.Now()
for i := 0; i < 1000; i++ {
for i := 0; i < 100; i++ {
str2 += "a"
}
}
t4 := time.Now()
fmt.Println(t4.Sub(t3))
str += "A"
}
out
build : 1.184106ms
str : 472.410119ms