3.1 整型

^操作符在go中有两个作用:

  1. 作为两元操作符时:x ^ y,按位异或,不同为1,相同为0
  2. 作为前置应让运算符:^y,按位取反

&^: z= x &^ y, 如果y在某个位置是1,就把x对应位置的数归零,如果y在某个位置是0,x对应的数字不变

1
fmt.Printf("%d %[1]o %#[1]o\n", o)
  • %[1]o: 以八进制打印第一个参数,[1]的意思是读取第一个参数,好处是不用多次传同一个参数
  • #: 对于对应进制会在前面强制补零

字符使用%c打印,带单引号的字符使用%q打印

1
2
3
4
5
6
7
ascii := 'a'
unicode := '国'
newline := '\n'
fmt.Printf("%d %[1]c %[1]q\n", ascii) // "97 a 'a'"
fmt.Printf("%d %[1]c %[1]q\n", unicode) // "22269 国 '国'"
fmt.Printf("%d %[1]q\n", newline) // "10 '\n'"

3.2 浮点数

math提供了正无穷和负无穷,用于表示太大溢出的数字和除零的结果,以及NaN非数,一般用于表示无效的除法操作,或者Sqrt(-1)

3.4 布尔型

布尔值可以和&&(AND)和||(OR)操作符结合,并且有短路行为:如果运算符左边值已经可以确定整个布尔表达式的值,那么运算符右边的值将不再被求值

&&的优先级比||高(助记:&&对应逻辑乘法,||对应逻辑加法,乘法比加法优先级要高)

3.5 字符串

字符串是不可变的,不可边指的是无法修改底层存放数据的区域,但是可以让变量指向一块新的内存区域

1
2
3
s := "left foot"
t := s
s += ", right foot"

t := s 发生了一次浅拷贝,只复制了s的结构体,s,t都指向同一个内存块,这是字符串拷贝非常快的原因,不用复制底层数据

s += ", right foot",在内存中找一个新地址,先把旧数据复制过去,然后再把新的数据追加过去,然后更新s,最后的结果就是,s指向了新的地址,t指向的还是原来的地址

ASCII控制代码转义方式:

1
2
3
4
5
6
7
8
9
10
\a      响铃
\b 退格
\f 换页
\n 换行
\r 回车
\t 制表符
\v 垂直制表符
\' 单引号(只用在 '\'' 形式的rune符号面值中)
\" 双引号(只用在 "..." 形式的字符串面值中)
\\ 反斜杠

UTF-8
定长编码(UTF-32):不管是字母A,还是复杂的汉字,通通占用4个字节,这很浪费空间
变长编码(UTF-8):
如果是 ASCII 字符(英文、数字):只占用 1 个字节。
如果是 常用字符(比如部分欧洲文字):占用 2 个字节。
如果是 汉字、日文:通常占用 3 个字节。
如果是 Emoji 表情:占用 4 个字节。

UTF-8利用每个字节的前面几位来标识这个字节是否读完了

  • 以0开头:告诉电脑结束了,这是一个完整的字符,保证了兼容性,可以兼容老旧的ASCII文件
  • 多个字节:
    • 110:表示后面还有一个字节(2字节)
    • 1110:后面还有2个字节(3字节)
    • 11110:后面还有3个字节(4字节)
      后续的字节以10开头

UTF8解码:显式

1
2
3
4
5
for i := 0; i < len(s); {
r, size := utf8.DecodeRuneInString(s[i:])
fmt.Printf("%d\t%c\n", i, r)
i += size
}

调用`DecodeRuneInString返回两个值,r是字符本身,size对应r在采用UTF-8编码后的编码字节数目
隐式:Go的range循环,在处理字符串的时候,会自动隐式解码

如果要将一个字符串解析为整数,可以使用strconv包的Atoi或ParseInt函数,还有用于解析无符号整数的ParseUint函数:

1
2
x, err := strconv.Atoi("123")             // x is an int
y, err := strconv.ParseInt("123", 10, 64) // base 10, up to 64 bits

3.6 常量

  • iota常量生成器
    第一个声明的常量所在的行,itoa为0, 然后在每一个有声明的行+1
1
2
3
4
5
6
7
8
9
10
11
type Weekday int

const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)

原文: “对于一个没有显式类型的变量声明(包括简短变量声明),常量的形式将隐式决定变量的默认类型,无类型整数常量转换为int,它的内存大小是不确定的”

写一个整数不告诉go是什么类型的时候,go会默认转为int类型,int是一个平台相关类型,
在32位系统, int = int32,
在64位系统,int = int64

原文: “但是无类型浮点数和复数常量则转换为内存大小明确的float64和complex128"

go中没有像int那样的通用float类型,所以无论是32还是64位的系统,永远转化为float64

为什么区别对待?

  • 整数通常用于数组下标,循环计数,这些操作依赖机器的字长
  • 科学计算和数值算法对精度极其敏感。如果在 32 位机器上默认是 float32(精度低),而在 64 位机器上默认是 float64(精度高)。那么对科学计算的影响很大