惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LangChain Blog
W
WeLiveSecurity
P
Proofpoint News Feed
月光博客
月光博客
NISL@THU
NISL@THU
L
LINUX DO - 最新话题
Webroot Blog
Webroot Blog
T
Threatpost
Y
Y Combinator Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Threat Research - Cisco Blogs
Vercel News
Vercel News
Jina AI
Jina AI
阮一峰的网络日志
阮一峰的网络日志
S
Schneier on Security
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
小众软件
小众软件
MyScale Blog
MyScale Blog
N
News and Events Feed by Topic
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
The Hacker News
The Hacker News
Schneier on Security
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Help Net Security
Help Net Security
Recent Announcements
Recent Announcements
S
Security @ Cisco Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Securelist
T
The Exploit Database - CXSecurity.com
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
雷峰网
雷峰网
量子位
Google DeepMind News
Google DeepMind News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
I
Intezer
T
The Blog of Author Tim Ferriss
G
GRAHAM CLULEY
D
DataBreaches.Net
V
Vulnerabilities – Threatpost
P
Privacy & Cybersecurity Law Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
罗磊的独立博客

NickChenyx's Blog

Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish Create_Rubbish
Create_Rubbish
nickChen · 2018-04-18 · via NickChenyx's Blog

Part1: array & slice

// define a slice
s := make([]int, 10)
// define an array
a := [10]int{}
  • 定义 slice 第一种方式
    var s []int
  • 定义 slice 第二种方式
    s := make([]int, len, cap)
  • array
    var a [length]type
    // var a [10]int

Part2: 类型

package main
import "fmt"
func main() {
    var a [8]int
    printArray(a)
}
func printArray(a [10]int) {
    fmt.Println(len(a))
    fmt.Println(cap(a))
}

以上代码中,printArray(a) 是否可以正常执行?答案是否定的,编译期就会提示错误

cannot use a (type [8]int) as type [10]int in argument to printArray

可以看到提示中变量 a 的类型是 type [8]int,而函数 printArray 要求的入参类型是 type [10]int。可见 array 的长度也是其类型的一部分!

Part3: slice grow

package main
import "fmt"
func main() {
    var s []int
    for i := 0; i < 1025; i++ {
        s = append(s, i)
    }
    fmt.Println(len(s)) // 1025
    fmt.Println(cap(s)) // 1280 = 1024*1.25
}

slice 扩容的方式是:source code

  • cap < 1024 –> cap * 2
  • cap > 1024 –> cap * 1.25

append 多个参数的对于 slice 容量的影响是不同的,特殊case:

package main
import "fmt"
func main() {
    var s1, s2, s3, s4, s5 []int
    s1 = append(s1, 0) // len 1, cap 1
    printSlice(s1)
    s2 = append(s2, 0, 1) // len 2, cap 2
    printSlice(s2)
    s3 = append(s3, 0, 1, 2) // len 3, cap 3
    printSlice(s3)
    s4 = append(s4, 0, 1, 2, 3) // len 4, cap 4
    printSlice(s4)
    s5 = append(s5, 0, 1, 2, 3, 4) // len 5, cap 6
    printSlice(s5)
}
func printSlice(s []int) {
    fmt.Println(len(s))
    fmt.Println(cap(s))
}

Part4: slice append
如何快速完成一次 slice 数据填充?

  1. 声明一个 slice 直接开始 append
  2. 声明固定长度 slice 后开始 append
  3. 声明固定长度 slice 后,使用 index 进行数据填充

可以看到方法三是最快的。

对于大数组的赋值,常用的优化方式还有一种 BCE,可以参考这篇文章中的用法,不再赘述。golang 边界检查优化

package main
import "testing"
func BenchmarkAppend(b *testing.B) {
    var s []int
    for i := 0; i < b.N; i++ {
        s = append(s, i)
    }
}
func BenchmarkMakeSliceAppend(b *testing.B) {
    s := make([]int, 0, b.N)
    for i := 0; i < b.N; i++ {
        s = append(s, i)
    }
}
func BenchmarkIndex(b *testing.B) {
    s := make([]int, b.N)
    for i := 0; i < b.N; i++ {
        s[i] = i
    }
}
// Output
// goos: darwin
// goarch: amd64
// cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
// BenchmarkAppend-8                457261122            14.93 ns/op
// BenchmarkMakeSliceAppend-8       1000000000             1.407 ns/op
// BenchmarkIndex-8                 1000000000             1.246 ns/op

Part5: slice 扩容带来的”意外”

当使用 index 修改 slice 时,可能会出现”时而生效时而不生效的情况”,究其原因是 slice 在 grow 的过程中重新分配了内存地址。

下面这个情况展示接收 slice 的函数 sliceAppend 修改了 index 但是在函数外不生效的情况。

package main
import "fmt"
func main() {
    var s []int
    s = append(s, 1)
    printSlice(s)
    sliceAppend(s)
    printSlice(s)
}
func sliceAppend(s []int) {
    s = append(s, 1) // 此处发生了扩容操作,导致 s 的内存地址改变
    s[0] = 0
    printSlice(s)
}
func printSlice(s []int) {
    fmt.Printf("len: %v, cap: %v, val: %v\n", len(s), cap(s), s)
}
// Output:
// len: 1, cap: 1, val: [1]
// len: 2, cap: 2, val: [0 1]
// len: 1, cap: 1, val: [1]

其实,扩容的发生导致函数内外的可见性也不一样了。和上个例子差不多的一个案例。
可以看到,此处两个 slice s 打印出来,结果是不一样的。看起来就是函数内的 s 比函数外的 s 数据更多了!换句话说,在实际场景中,很有可能因为如下这样的误操作,导致看似操作过 s,但是数据缺丢失了。

package main
import "fmt"
func main() {
    var s []int
    s = append(s, 1)
    printSlice(s)
    sliceAppend(s)
    printSlice(s)
}
func sliceAppend(s []int) {
    s = append(s, 1) // 此处发生了扩容操作,导致 s 的内存地址改变
    printSlice(s)
}
func printSlice(s []int) {
    fmt.Printf("len: %v, cap: %v, val: %v\n", len(s), cap(s), s)
}
// Output:
// len: 1, cap: 1, val: [1]
// len: 2, cap: 2, val: [1 1]
// len: 1, cap: 1, val: [1]

!!如果发生了扩容,修改会在新的内存中!!

所以针对 slice 的操作,务必使用 append 函数返回的 slice 对象进行后续操作,避免出现奇怪的数据异常!

Part6: slice 序列化

如下案例所示,slice 的 zero value 经过默认的 json 库序列化结果是 null,但是初始化的 slice 经过默认的 json 库序列化结果就是 []

package main
import (
    "encoding/json"
    "fmt"
)
func main() {
    var s []int
    b, _ := json.Marshal(s)
    fmt.Println(string(b))
}
// Output:
// null
package main
import (
    "encoding/json"
    "fmt"
)
func main() {
    s := []int{}
    b, _ := json.Marshal(s)
    fmt.Println(string(b))
}
// Output:
// []
package main
import (
    "encoding/json"
    "fmt"
)
func main() {
    s := make([]int, 0, 1)
    b, _ := json.Marshal(s)
    fmt.Println(string(b))
}
// Output:
// []
package main
import (
    "encoding/json"
    "fmt"
)
func main() {
    s := make([]int, 1)
    b, _ := json.Marshal(s)
    fmt.Println(string(b))
}
// Output:
// [0]

TODO 如果有更多再补充


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 nickchenyx@gmail.com