Golang 语法相关笔记

摘抄

Basic Types

推荐用 new 来创建指针, int 类型还有对应的 untype 类型,作为对应的编译器常量,精度在 256 bits 以上。

Numbers

只有 intergers 有跟随编译器变化位数的 int 类型,其他都指定了位数,例如只有 float64 类型没有 float 类型。

intergers

一般和外界对接要指明符号和大小,但程序内更推荐使用int。

floating-point numbers

complex numbers

Strings

string 都是 immutable 的,所以直接拼接 string 很浪费内存,类似 java 中的 StringBuilder,Go 中有 bytes.Buffer 来临时存放字符,最后再转化成 string。

所有 string 采用 UTF-8 编码,因此 string 的 len 不是其字符数量(UTF-8 编码有可能超过一个 byte),可以用 utf8.RuneCountInString 来获得其中 rune 字符的长度。

rune 代表一个 UTF-8 字符,格式为:

UTF-8 有如下特性:

Booleans

Aggregate Types

Arrays

array 可以在初始化的时候指定每一位的元素值,如下面例子

type Currency int

const (
		USE Currency = iota
		EUR
		GBP
		RMB
)

symbol := […]string{USD: “$”, EUR: “€”, GBP:”£”, RMB: “¥”}

fmt.Println(RMB, symbol[RMB]) // “3 ¥”

Structs

Reference Types

Pointers

For a of pointer to array type: a[x] is shorthand for (*a)[x]

If a is a pointer to an array, a[low : high] is shorthand for (*a)[low : high].

If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()

statement *p++ is the same as (*p)++.

Slices

slice 之间不能用 == 比较符号。

唯一被允许的比较是 slice == nil,为 slice 内置 == 比较符号会有一些deep comparison的问题:

  1. array 不一样, slice 的底层数据结构是 indirect 的,甚至可能出现一个 slice 中的元素引用这个 slice 的情况。
  2. slice 的底层 array 是有可能被改变的,移除内置 ==slice 无法作为 mapkey

Maps

Spec

map 中的 value 无法被取地址,这是为了防止 rehash 导致地址变化带来问题。因此你无法对 map 中的 value 唤起 pointer method,因为没有地址可传入。

mapslice 一样,没有内置的 == 操作

数据结构

type hmap struct { ... } ,其中 B uint8 代表当前哈希表持有的 buckets 数量的 2 次幂,即 len(buckets) = 2B2^B

每个 bucket 对应的是 runtime.bmap,一个 bucket 会存 8 个键值对,一旦桶溢出,多余的键值对则会转移到溢出桶。

寻址

用 key hash 的后面几位决定目标桶,用 key hash 的前 8 位比较 key 是否相等。

for loop 时 runtime 会 random 出一个起点,如果中途修改 map 中的 kv,被修改的 kv 能否被遍历到取决于修改时 iterator 的位置是否在被修改 kv 的前面。

扩容

扩容不会修改 hash 因子,在扩容期间向旧桶写入、删除数据时会引发旧桶数据向新桶分流。

Functions

注意 receiver 定义为指针类型的情况,调用时就自动转化 value 为指针的默认行为是为了方便指针方法修改 receiver 内部状态,如果 receiver 是 value 其内部状态就不会被修改。这一点和 C 的 const 有点类似。

Channels

从已经关闭的 channel 接收消息会立即得到零值,可以用 _, ok := <-ch 的方法判断 channel 是否已经关闭。

close 已关闭的 channel 或者 nil channel 会导致 panic。

nil channel 接收消息会 block forever。

channel 的计算效率目前和直接使用锁相比并不高。

Interfaces

一个 interface 里包含了两个值,代表其指向元素的 typevalue ,因此 val i interface{} := new(SomeType) 中的 i 并不等于 nil ,因为它还包含了一个 type 值。

Basic interfaces

Embedded interfaces

General interfaces

类型比较

  1. A named type is always different from any other type;
  2. Otherwise, two types are identical if their underlying type literals are structurally equivalent.

whether two values may be compared with == and != is related to assign ability to: in any comparison, the first operand must be assignable to the type of the second operand or vice versa.

Arithmetic operators apply to numeric values and yield a result of the same type as the first operand.

Range

range 右边的表达式叫做 range expression

range expression 的 core type 只能是:

range 关键词本质上是一个语法糖,其在编译后会被展开为一个 for,针对不同结构体,展开结果不同,大致形式为:

ha := a
hv1 := 0
hn := len(ha)
v1 := hv1
v2 := nil
for ; hv1 < hn; hv1++ {
		tmp := ha[hv1]
		v1, v2 = hv1, tmp
		...
}
Core type

non-interface 的 core type 和其 underlying type 一样

interface在这两种情况下有core type

  1. 其 type set 中的所有 type 有相同的一个 underlying type U,那么其 core type 为 U
  2. type set 只有 channel type,方向相同,返回的都是 type E,那么其 core type 为 E

创建变量

没有被给定指定值的变量都会被赋予zero value。

定义变量只是定义变量之间的DAG,真正的初始化从第一个没有依赖其他变量的变量开始。https://go.dev/ref/spec#Package_initialization

占位符

%d 十进制整数

%x %o %b 十六进制、八进制、二进制整数

%f %g %e 浮点数,e 表示 3.1415923e+00 的形式,g 指根据情况选择 f 或 e 输出(看哪个输出格式更紧凑)。All three verbs allow field width and numeric precision to be controlled.

%t 布尔值

%c rune、unicode code point

%s 字符串、凡是实现了Stringer interface的类型都适用

%q quoted string “abc” or rune ‘c'

%v any value in a natural format

%T type of any value

%% literal percent sign (no operand)

%w error values

%[1]d 代表把 format 的第一个参数用十进制整数的形式打印出来,这样多个占位符可以用上相同的参数。举个例子:

	fmt.Sprintf("%[2]d %[1]d\n", 11, 22) // "22 11"

%#d 代表把前面表示进制(0、0x)的前缀给打印出来

% x,中间有个空格,代表把数字中的每个元素按照 %x 的格式打印出来,每个元素之间用空格分隔。

JSON

JSON marshal是依赖反射读取field tag以实现序列化

https://github.com/bytedance/mockey 中的 mock 是如何实现的

通过替换函数对应地址的字节码,将函数调用引导进 mock 函数。