1. 布尔类型
布尔类型用于表示真假,类型名为bool,只有两个值true和false,占用一个字节宽度,零值为false;
两个类型相同的值可以使用相等 == 或者不等 != 运算符来进行比较并获得一个布尔型的值;
当相等运算符两边的值是完全相同的值的时候会返回true,否则返回false,并且只有在两个的值的类型相同的情况下才可以使用;
示例:
var aVar = 10
aVar == 5 --> false
aVar == 10 --> true
var aVar = 10
aVar != 5 -> true
aVar != 10 -> false
Go对于值之间的比较有非常严格的限制,只有两个类型相同的值才可以进行比较,如果值的类型是接口(interface),它们也必须都实现了相同的接口;如果其中一个值是常量,那么另外一个值的类型必须和该常量类型相兼容的;如果以上条件都不满足,则其中一个值的类型必须在被转换为和另外一个值的类型相同之后才可以进行比较;
布尔型的常量和变量也可以通过和逻辑运算符(非 !
、和 &&
、或 ||
)结合来产生另外一个布尔值,这样的逻辑语句就其本身而言,并不是一个完整的Go语句;
使用T来代表条件符合的语句,用F来代表条件不符合的语句;
非运算符:!
!T -> false
!F -> true
和运算符:&&
T && T -> true
T && F -> false
F && T -> false
F && F -> false
或运算符:||
T || T -> true
T || F -> true
F || T -> true
F || F -> false
在格式化输出时,使用%t
占位符来表示要输出的值为布尔型
fmt.Printf("isBody=%t, isGirl=%t\n", isBody, isGirl)
布尔值(以及任何结果为布尔值的表达式)最常用在条件结构的条件语句中,例如:if、for和switch结构
对于布尔值的好的命名能够很好地提升代码的可读性,例如以is或者Is开头的isSorted、isFinished、isVisible;
2. 数值类型
2.1 整型
Go语言提供了5种有符号、5种无符号、1种指针、1种单字节、1种单个unicode字符(unicode码点),共13种整数类型,零值均为0
类型名 | 字节宽度 | 说明&取值范围 |
---|---|---|
int | 32位系统4字节,64位系统8字节 | 有符号整型 |
uint | 32位系统4字节,64位系统8字节 | 无符号整型 |
rune | 4 字节 | Unicode码点,取值范围同uint32 |
int8 | 1 字节 | 用 8 位表示的有符号整型,取值范围为:[-128,127] |
int16 | 2 字节 | 用 16 位表示的有符号整型,取值范围为:[-32768,32767] |
int32 | 4 字节 | 用 32 位表示的有符号整型,取值范围为:[-2147483648,2147483647] | |
| int64 | 8 字节 | 用 64 位表示的有符号整型,取值范围为:[-9223372036854775808,9223372036854775807] |
uint8 | 1 字节 | 用8位表示的无符号整型,取值范围为:[0,255] |
uint16 | 2 字节 | 用 16 位表示的无符号整型,取值范围为:[0,65535] |
uint32 | 4 字节 | 用 32 位表示的无符号整型,取值范围为:[0,4294967295] |
uint64 | 8 字节 | 用 64 位表示的无符号整型,取值范围为:[0,18446744073709551615] |
byte | 1 字节 | 字节类型,取值范围同uint8 |
uintptr | 32位系统4字节,64位系统8字节 | 指针值的无符号整型 |
字面量:
- 十进制表示法:以10为基数,采用0-9十个数字,逢10进位,例如:10
- 八进制表示法:以8为基数,采用0-7八个数字,逢8进位,使用0开头表示为八进制表示,例如:010
- 十六进制表示法:以16为基数,采用0-9十个数字和A-F六个字母,逢16进位,使用0X 开头表示为十六进制 ,例如:0X10
常用操作:
var n1, n2, n3 int = 1, 8, -2
var n4 uint = 2
2.1.1 算术运算符
+、-、*、/、%、++、—
注意:针对/除数不能为0,且结果依然为整数
// 算术运算
fmt.Println(1 + 2) // 3
fmt.Println(1 - 2) // -1
fmt.Println(1 * 2) // 2
fmt.Println(1 / 2) // 0 int/int => 向下取整
fmt.Println(1 % 2) // 1
n1++
n2--
fmt.Println(n1,n2)
2.1.2 关系运算符
、>=、<、<=、==、!=
fmt.Println(1 > 2) // false
fmt.Println(1 >= 2) // false
fmt.Println(1 < 2) // true
fmt.Println(1 <= 2) // true
fmt.Println(1 != 2) // true
fmt.Println(1 == 2) // false
2.1.3 位运算符
&、|、, 两个整数转为二进制进行计算 对应的位进行计算
- & 两个为1 => 1
- | 只要有一个为1 => 1
- ^ 抑或 相同->0, 不同->1
- << 10 => 2 ^ n
0 => /2^n
- &^ a &^ b 擦除 b(1->a->0)
对于负整数在计算机中使用补码进行表示,对应正整数二进制表示取反+1
针对左、右移的右操作数必须为无符号整型
// 2 => 0010
// 7 => 0111
// -2 => 1110
fmt.Println(n1 & n2) // 0010
fmt.Println(n1 | n2) // 0111
fmt.Println(n1 ^ n2) // 0101
fmt.Println(n1 &^ n2) // 0000
fmt.Println(n2 << n4) // 0001 1100
fmt.Println(n2 >> n4) // 0001
fmt.Println(n3 << n4) // 1111 1000
fmt.Println(n3 >> n4) // 1111 1111
2.1.4 赋值运算符
=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
n1 += n2 => n1 = n1 + n2
n1 -= n2 => n1 = n1 - n2
n4 <<= n4
fmt.Println(n1, n2, n4)
2.1.5 类型转换
Go不会自动对数据类型转换,因此左、右操作数类型必须一致或某个字面量,可通过类型名(数据)的语法将数据转换为对应类型。需要注意值截断和值溢出问题
使用fmt.Printf进行格式化参数输出,占位符:
- %b: 二进制
- %c: 字符
- %d: 十进制
- %+d: 表示对正整数带+符号
- %nd: 表示最小占位n个宽度且右对齐
- %-nd: 表示最小占位n个宽度且左对齐
- %0nd: 表示最小占位n个宽度且右对齐,空字符使用0填充
- %o: 八进制,%#o带0的前缀
- %x、%X: 十六进制,%#x(%#X)带0x(0X)的前缀
- %U: Unicode码点,%#U带字符的Unicode码点
- %q: 带单引号的字符
常用包:
- math
- math/rand
2.1.6 随机数
random.go:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
for i := 0; i <= 10; i++ {
a := rand.Int()
fmt.Printf("%d /", a)
}
for i := 0; i < 5; i++ {
r := rand.Intn(8)
fmt.Printf("%d /", r)
}
fmt.Println()
timens := int64(time.Now().Nanosecond())
rand.Seed(timens)
for i := 0; i < 10; i++ {
fmt.Printf("%2.2f /", 100*rand.Float32())
}
}
可能的输出:
5577006791947779410 /8674665223082153551 /6129484611666145821 /4037200794235010051 /3916589616287113937 /6334824724549167320 /605394647632969758 /1443635317331776148 /894385949183117216 /2775422040480279449 /4751997750760398084 /7 /2 /1 /0 /2 /
31.11 /97.12 /90.94 /79.13 /16.71 /30.78 /83.68 /19.42 /55.64 /10.45 /
使用rand.Seed(value)函数来提供伪随机数的生成种子,一般情况下都会使用当前时间的纳秒级数字
2.1.7 运算符与优先级
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右
优先级 运算符
7 ^ !
6 * / % << >> & &^
5 + - | ^
4 == != < <= >= >
3 <-
2 &&
1 ||
当然,可以通过使用括号来临时提升某个表达式的整体运算优先级
2.1.8 类型别名
在使用某个类型时,可以给它起另一个名字,可以在代码中使用新的名字(用于简化名称或解决名称冲突)
在 type TZ int
中,TZ就是int类型的新名称(用于表示程序中的时区),然后就可以使用TZ来操作int类型的数据
type.go:
import "fmt"
type TZ int
func main() {
var a,b TZ = 3,4
c:=a+b
fmt.Printf("c has the value: %d \n",c)
}
实际上,类型别名得到的新类型并非和原类型完全相同,新类型不会拥有原类型所附带的方法;TZ 可以自定义一个方法用来输出更加人性化的时区信息
2.1.9 字符类型
包 unicode 包含了一些针对测试字符的非常有用的函数(其中 ch 代表字符):
- 判断是否为字母:unicode.IsLetter(ch)
- 判断是否为数字:unicode.IsDigit(ch)
- 判断是否为空白符号:unicode.IsSpace(ch)
2.2 浮点型
浮点数用于表示带小数的数字,Go提供float32和float64两种浮点类型
字面量:
- 十进制表示法:3.1415926
- 科学计数法:1e-5
常用操作:
2.2.1 算术运算符
+、-、*、/、++、—
注意:针对/除数不能为0
fmt.Println(1.2 + 1.1)
fmt.Println(1.2 - 1.1)
fmt.Println(1.2 * 1.1)
fmt.Println(1.2 / 1.1)
height := 1.69
height++
fmt.Println(height)
height--
fmt.Println(height)
2.2.2 关系运算符
、>=、<、<=
浮点型不能进行==或!=比较,可选择使用两个浮点数的差在一定区间内则认为相等
fmt.Println(1.1 > 1.2)
fmt.Println(1.1 >= 1.2)
fmt.Println(1.1 < 1.2)
fmt.Println(1.1 <= 1.2)
2.2.3 赋值运算符
=、+=、-=、*=、/=
a += b a = a + b
2.2.4 类型转换
Go 不会对自动对数据类型转换,因此左、右操作数类型必须一致或某个字面量,可通过 类型名(数据)的语法将数据转换为对应类型。需要注意值截断和值溢出问题
fmt.Printf("%T %T\n", f1, float64(f1))
使用fmt.Printf进行格式化参数输出,占位符:
- %f、%F:十进制表示法
- %n.mf表示最小占n个宽度并且保留m位小数
- %e、%E:科学记数法表示
- %g、%G:自动选择最紧凑的表示方法%e(%E)或%f(%F)
常用包:
- math
- math/rand
2.3 复数型
Go 提供 complex64 和 complex128 两种复数类型,针对 complex64 复数的实部和虚部均使用 float32,针对 complex128 复数的实部和虚部均使用 float64
字面量:
- 十进制表示法:1 + 2i,, i*i = -1, 1 为实部,2 为虚部
常用函数:
- complex: 工厂函数,通过两个参数创建一个复数
- real:用于获取复数的实部
- imag: 用于获取复数的虚部
常用包:
- math/cmplx
3.字符串类型
字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节)。UTF-8 是被广泛使用的编码格式,是文本文件的标准编码,其它包括 XML 和 JSON 在内,也都使用该编码。由于该编码对占用字节长度的不定性,Go 中的字符串里面的字符也可能根据需要占用 1 至 4 个字节,这与其它语言如 C++、Java 或者 Python 不同(Java 始终使用 2 个字节)。Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。
字符串是一种值类型,且值不可变,即创建某个文本后无法再次修改这个文本的内容;更深入地讲,字符串是字节的定长数组。
使用string表示。
字面量:
- 可解析字符串:通过双引号(“)来创建,不能包含多行,支持特殊字符转义序列
- 原生字符串:通过反引号(`)来创建,可包含多行,不支持特殊字符转义序列
特殊字符:
- \: 反斜线
- \’: 单引号
- \”: 双引号
- \a: 响铃
- \b: 退格
- \f: 换页
- \n: 换行
- \r: 回车
- \t: 制表符
- \v: 垂直制表符
- \ooo: 3个8位数字给定的八进制码点的Unicode字符(不能超过\377)
- \uhhhh:4个16位数字给定的十六进制码点的Unicode字符
- \Uhhhhhhhh:8个32位数字给定的十六进制码点的Unicode字符
- \xhh:2个8位数字给定的十六进制码点的Unicode字符
常用操作:
- 字符串连接:+
- 关系运算符:>、>=、<、<=、==、!=
- 赋值运算符:+=
- 索引:s[index], 针对只包含ascii字符的字符串
- 切片:s[start:end], 针对只包含ascii字符的字符串
常用函数:
- len: 获取字符串长度(针对只包含ascii字符的字符串)
- string: 将byte或rune数组转换为字符串
使用fmt.Printf进行格式化参数输出,占位符:
- %s
常用包:
- fmt
- strings
- strconv
- unicode
- unicode/utf8
- bytes
- regex
3.1 strings包
Go 中使用 strings 包来完成对字符串的主要操作。
3.1.1 前缀和后缀
HasPrefix 判断字符串 s 是否以 prefix 开头:
strings.HasPrefix(s, prefix string) bool
HasSuffix 判断字符串 s 是否以 suffix 结尾:
strings.hasSuffix(s, suffix string) bool
presuffix.go:
package main
import (
"fmt"
"strings"
)
func main() {
var str string = "This is an example of a string"
fmt.Printf("T/F? Does the string \"%s\" have prefix %s?\n", str,"Th")
fmt.Printf("%t\n",strings.HasPrefix(str,"Th"))
}
T/F? Does the string "This is an example of a string" have prefix Th?
true
3.1.2 字符串包含关系
Contains 判断字符串 s 是否包含 substr:
strings.Contains(s, substr string) bool
3.1.3 判断子字符串或字符在父字符串中出现位置(索引)
Index 返回字符串 str 在字符串 s 中的索引(str 的第一个字符的索引),-1 表示字符串s 不包含字符串 str:
strings.Index(s, str string) int
LastIndex 返回字符串 str 在字符串 s 中最后出现位置的索引(str 的第一个字符的索引),-1 表示字符串 s 不包含字符串 str:
string.LastIndex(s, str string) int
如果需要查询非ASCII编码的字符在父字符串中的位置,建议使用以下函数来对字符进行定位:
strings.IndexRune(s string, r rune) int
3.1.4 字符串替换
Replace 用于将字符串 str 中的前 n 个字符串 old 替换为字符串 new,并返回一个新的字符串,如果 n = -1 则替换所有字符串 old 为字符串 new:
strings.Replace(str, old, new, n) string
3.1.5 统计字符串出现次数
Count 用于计算字符串 str 在字符串 s 中出现的非重叠次数:
strings.Count(s, str string) int
3.1.6 重复字符串
Repeat 用于重复 count 次字符串 s 并返回一个新的字符串:
strings.Repeat(s, count int) string
3.1.7 修改字符串大小写
ToLower 将字符串中的Unicode字符全部转换为相应的小写字符:
strings.ToLower(s) string
ToUpper 将字符串中的Unicode字符全部转换为相应的大写字符:
strings.ToUpper(s) string
3.1.8 修剪字符串
使用 strings.TrimSpace(s) 来剔除字符串开头和结尾的空白符号;剔除指定字符,则可以使用 strings.Trim(s, “cut”) 来将开头和结尾的 cut 去除掉。该函数的第二个参数可以包含任何字符,剔除开头或者结尾的字符串,则可以使用 TrimLeft 或者 TrimRight 来实现。
3.1.9 分割字符串
strings.Fields(s) 将会利用 1 个或多个空白符号来作为动态长度的分隔符将字符串分割成若干小块,并返回一个 slice,如果字符串只包含空白符号,则返回一个长度为 0 的 slice。
strings.Split(s, sep) 用于自定义分割符号来对指定字符串进行分割,同样返回 slice。
因为这 2 个函数都会返回 slice,所以习惯使用 for-range 循环来对其进行处理。
3.1.10 拼接slice到字符串
Join 用于将元素类型为string的slice使用分割符号来拼接组成一个字符串:
strings.Join(sl []string, sep string) string
strings_splitjoin.go:
package main
import (
"fmt"
"strings"
)
func main() {
str := "The quick brown fox jumps over the lazy dog"
sl := strings.Fields(str)
fmt.Printf("Splitted in slice: %v\n", sl)
for _, val := range sl {
fmt.Printf("%s - ", val)
}
fmt.Println()
str2 := "GO1|The ABC of Go|25"
sl2 := strings.Split(str2, "|")
fmt.Printf("Splitted in slice: %v\n", sl2)
for _, val := range sl2 {
fmt.Printf("%s - ", val)
}
fmt.Println()
str3 := strings.Join(sl2,";")
fmt.Printf("sl2 joined by ;: %s\n", str3)
}
Splitted in slice: [The quick brown fox jumps over the lazy dog]
The - quick - brown - fox - jumps - over - the - lazy - dog -
Splitted in slice: [GO1 The ABC of Go 25]
GO1 - The ABC of Go - 25 -
sl2 joined by ;: GO1;The ABC of Go;25
3.1.11 从字符串中读取内容
函数 strings.NewReader(str) 用于生成一个 Reader 并读取字符串中的内容,然后返回指向该 Reader 的指针,从其它类型读取内容的函数
还有:
- Read() 从 []byte 中读取内容。
- ReadByte() 和 ReadRune() 从字符串中读取下一个 byte 或者 rune。
3.2 strconv包
3.2.1 数字类型转换到字符串
- strconv.Itoa(i int) string 返回数字i所表示的字符串类型的十进制数;
- strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string 将 64 位浮点型的数字转换为字符串,其中 fmt 表示格式(其值可以是 ‘b’、’e’、’f’ 或 ‘g’),prec 表示精度,bitSize 则使用 32 表示 float32,用 64 表示 float64。
注意:将字符串转换为其它类型 tp 并不总是可能的,可能会在运行时抛出错误 parsing "…": invalid argument
。
3.2.2 字符串类型转换为数字类型
- strconv.Atoi(s string) (i int, err error) 将字符串转换为 int 型。
- strconv.ParseFloat(s string, bitSize int) (f float64, err error) 将字符串转换为 float64 型。
利用多返回值的特性,这些函数会返回 2 个值,第 1 个是转换后的结果(如果转换成功),第 2 个是可能出现的错误,因此,我们一般使用以下形式来进行从字符串到其它类型的转换:
val, err = strconv.Atoi(s)
4. 枚举类型
常使用 iota 生成器用于初始化一系列相同规则的常量,批量声明常量的第一个常量使用 iota 进行赋值,此时 iota 被重置为 0,其他常量省略类型和赋值,在每初始化一个常量则加1
enum.go:
package main
import "fmt"
// 枚举
const (
c1 int = iota
c2
c3 int = iota
c4
)
func main() {
const (
c5 = iota
c6
c7 = 7
c8
c9 = iota
c10
)
fmt.Println(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10)
}
0 1 2 3 0 1 7 7 4 5
5. 指针类型
每个变量在内存中都有对应存储位置(内存地址),可以通过&运算符获取。指针是用来存储 变量地址的变量
5.1 声明
指针声明需要指定存储地址中对应数据的类型,并使用*作为类型前缀。指针变量声明后会被初始化nil,表示空指针
var pointer01 *int
var pointer02 *float64
var pointer03 *string
fmt.Printf("%T, %T, %T\n", pointer01, pointer02, pointer03)
fmt.Println(pointer01, poniter02, pointer03)
fmt.Printf("%t, %t, %t\n", pointer01 == nil, pointer02 == nil, poniter03 == nil)
5.2 初始化
- 使用&运算符+变量初始化:&运算获取变量的存储位置来初始化指针变量
- 使用new函数初始化:new函数根据数据类型申请内存空间并使用零值填充,并返回申请空间地址
5.3 操作
可通过*运算符+指针变量名来访问和修改对应存储位置的值
5.4 指针的指针
用来存储指针变量地址的变量叫做指针的指针
5.5 实例
point.go
package main
import "fmt"
func main() {
// 指针
// 值类型
// 赋值 原有的数据复制一份给新的变量
// 两个变量之间没有任何联系
// 对nums进行任何修改都不会影响nums2
// 对nums2进行任何修改也不会影响nums
// 有联系 => 引用类型(内部使用使用了指针/地址)
// 数组值类型
nums := [5]int{1, 2, 3, 4, 5}
nums2 := nums
fmt.Println(nums, nums2)
nums2[0] = 100
fmt.Println(nums, nums2)
// int, float, bool, string => 值类型
// var name *type
var age = 1
var agePointer *int = nil // 定义int类型的指针
agePointer = &age // 取出age的地址赋值给agePointer => 取引用
fmt.Println(agePointer, age)
fmt.Println(*agePointer) // 获取agePointer内存地址中对应的存储的值 => 解引用
*agePointer = 33
fmt.Println(age, *agePointer)
var numsPoint *[5]int = &nums
fmt.Printf("%T\n", numsPoint)
numsPoint[0] = 100
fmt.Println(nums, numsPoint)
}