Skip to content

Commit 295b34a

Browse files
committed
docs(slice): slice parameter
1 parent a72061c commit 295b34a

File tree

5 files changed

+32
-18
lines changed

5 files changed

+32
-18
lines changed

content/docs/basic/01_basic_type.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ type StringHeader struct {
6868

6969
#### `+` 拼接字符串
7070

71-
例如 `fmt.Println("hello" + s[5:])` 输出 `"hello, world"`。使用 `+` 来拼接两个字符串时,它会申请一块新的内存空间,大小是两个字符串的大小之和。拼接第三个字符串时,再申请一块新的内存空间,大小是三个字符串大小之和。这种方式每次运算都需要重新分配内存,会给内存分配和 GC 带来额外的负担,所以性能比较差。
71+
例如 `fmt.Println("hello" + s[5:])` 输出 `"hello, world"`。使用 `+` 来拼接两个字符串时,它会申请一块新的内存空间,大小是两个字符串的大小之和。
72+
拼接第三个字符串时,再申请一块新的内存空间,大小是三个字符串大小之和。**这种方式每次运算都需要重新分配内存,会给内存分配和 GC 带来额外的负担,所以性能较差**
7273

7374
#### fmt.Sprintf
7475

content/docs/basic/03_slice.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -124,30 +124,38 @@ package main
124124
import "fmt"
125125

126126
func appendFunc(s []int) {
127-
s = append(s, 10, 20, 30)
127+
s = append(s, 10, 20, 30)
128128
}
129129

130130
func appendPtrFunc(s *[]int) {
131131
*s = append(*s, 10, 20, 30)
132132
}
133133

134134
func main() {
135-
sl := make([]int, 0, 10)
136-
137-
appendFunc(sl)
138-
// appendFunc 修改的是 sl 的副本,len 和 cap 并没有被修改,下面的输出是 []
139-
fmt.Println(sl) // []
140-
// appendFunc,虽然没有修改 len 和 cap,但是底层数组是被修改了的,所以下面的输出会包含 10 20 30
141-
fmt.Println(sl[:10]) // [10 20 30 0 0 0 0 0 0 0]
142-
// 为什么 sl[:10] 和 sl[:] 的输出不同,是因为 go 的切片的一个优化
143-
// slice[low:high] 中的 high,最大的取值范围对应着切片的容量(cap),不是单纯的长度(len)。
144-
// sl[:10] 可以输出容量范围内的值,并且没有越界。
145-
// sl[:] 由于 len 为 0,并且没有指定最大索引。high 则会取 len 的值,所以输出为 []
146-
fmt.Println(sl[:]) // []
135+
sl := make([]int, 0, 10)
136+
137+
appendFunc(sl)
138+
// appendFunc 修改的是 sl 的副本
139+
// 副本的 struct {
140+
// Data uintptr
141+
// Len int
142+
// Cap int
143+
// }
144+
// 副本的 len 和 cap 被修改了,但是不会影响外部 slice 的 len 和 cap,所以下面的输出是 []
145+
fmt.Println(sl) // []
146+
// appendFunc,虽然没有修改外部 slice 的 len 和 cap,
147+
// 但是副本 `Data uintptr` 是一个指针的拷贝,和外部 slice 指向的是同一个底层数组
148+
// 所以底层数组最终是被修改了的,所以下面的输出会包含 10 20 30
149+
fmt.Println(sl[:10]) // [10 20 30 0 0 0 0 0 0 0]
150+
// 为什么 sl[:10] 和 sl[:] 的输出不同,是因为 go 的切片的一个优化
151+
// slice[low:high] 中的 high,最大的取值范围对应着切片的容量(cap),不只是单纯的长度(len)。
152+
// sl[:10] 可以输出容量范围内的值,并且没有越界。
153+
// sl[:] 由于 len 为 0,并且没有指定最大索引。high 则会取 len 的值,所以输出为 []
154+
fmt.Println(sl[:]) // []
147155

148156
slptr := make([]int, 0, 10)
149157
appendPtrFunc(&slptr)
150-
// 这里传入的是切片的指针,会改变外层的 slptr
158+
// 这里传入的是切片的指针,会改变外部的 slice slptr
151159
fmt.Println(slptr) // [10 20 30]
152160
}
153161
```

content/docs/basic/05_function.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ weight: 5
1010
- 值传递:当传一个参数值到被调用的函数里面时,实际上是传了这个值的副本,被调用方和调用方两者持有不相关的两份数据。
1111
- 引用传递:当传一个参数值到被调用的函数里面时,实际是传了参数的指针,被调用方和调用方两者持有相同的数据,任意一方做出的修改都会影响另一方。
1212

13-
Go 使用的是**值传递,不管参数是基本类型,结构体还是指针,都会对传递的参数进行拷贝,区别无非是拷贝的目标对象还是拷贝指针**。拷贝指针,也就是会同时出现两个指针指向原有的内存空间。
13+
Go 使用的是**值传递,不管参数是基本类型,结构体还是指针,都会对传递的参数进行拷贝,区别无非是拷贝的目标对象还是拷贝指针**
14+
15+
{{< callout type="info" >}}
16+
拷贝指针,也就是会同时出现两个指针指向原有的内存空间。
17+
{{< /callout >}}
18+
1419

1520
```go
1621
package main

content/docs/practice/06_performance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func main() {
171171

172172
编译器决定内存分配位置的方式,就称之为**逃逸分析**(escape analysis)。逃逸分析由编译器完成,作用于编译阶段。
173173

174-
变量逃逸是指编译器将一个变量从栈上分配到对上的情况
174+
变量逃逸是指编译器将一个变量从栈上分配到堆上的情况
175175

176176
在 Go 中,栈是跟函数绑定的,函数结束时栈被回收。如果一个变量分配在栈中,则函数执行结束可自动将内存回收。如果分配在堆中,则函数执行结束可交给 GC(垃圾回收)处理。
177177

content/docs/project/16_casbin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ m = r.sub == p.sub && ReverseMatch(r.obj, p.obj) && r.act == p.act
683683

684684
## Enforcer
685685

686-
Casbin [Enforcer(https://casbin.org/zh/docs/enforcers) 执行器往内存中缓存策略数据时并**不是并发安全**的,
686+
Casbin [Enforcer](https://casbin.org/zh/docs/enforcers) (执行器)往内存中缓存策略数据时并**不是并发安全**的,
687687
所以 Casbin 还实现了多种 `Enforcer`,可以分为并发安全的 `SyncedEnforcer`,带缓存的 `CachedEnforcer` 等等。
688688

689689
- `Enforcer`:基础的执行器,内存中的操作不是并发安全的。

0 commit comments

Comments
 (0)