读书笔记【一】:数组、字符串、切片

  • Go语言的赋值和函数传参规则:除了闭包函数以引用的方式对外部变量访问之外,其他赋值和函数传参都是以传值的方式处理。
  • 数组的长度是数组类型的组成部分,不同长度或不同类型的数据组成的数据都是不同的类型,不同长度的数组因为类型不同而无法直接赋值,
数组
  • Go语言的数组是值语义。一个数组变量即表示整个数组,它并不是隐式地指向第一个元素的指针,而是一个完整的值。每一次传递或者赋值实际上都是赋值整一个数组,为了避免复制数组带来的开销,可以传递一个指向数组的指针,但是数组指针并不是数组。但是指向不同长度的数组指针的指针类型是完全不同的。
// 接口数组
var unknown1 []interface{}
var unknown2 =[...]interface{1243, "hello"}

// 空数组
var d [0]int
var e =[0]int{}

//长度为0的数组在内存中并不占用空间,空数组虽然很少直接使用,但是可以强调某种特有类型的操作时避免分配额外的空间,例如用于通道的同步操作
c1 := make(chan [0]int)
go func() {
	fmt.Println("c1")
	c1 <- [0]int{}
}()
<-c1

// 一般更倾向于用无类型的匿名结构体代替空数组
c2 := make(chan struct{})
go func() {
	fmt.Println("c2")
	c2 <- struct{}{}
}()
<-c2
字符串
  • Go语言的源代码要求UTF8编码,导致字符串面值常量一般也是UTF8编码。源代码中的文本字符串通常被解释为采用UTF8的Unicode码点序列。
  • for range等语法不支持非UTF8编码的字符串的遍历
type StringHeader struct {
	Data uintptr
	Len int 
}
  • 字符串结构由两个信息组成
    • 字符串指向的底层字节数组
    • 字符串的字节的长度。
  • 字符串其实也是一个结构体,因此字符串的赋值操作也就是reflect.StringHeader结构体的复制过程,并不会涉及到底层字节数组的复制。因为字符串是只读的,所以相同的字符串面值常量通常对应同一个字符串常量。
  • 字符串和[]rune的转换比较特殊,因为他们的底层类型不一样([]byte,[]int32)。因此这种转换可能隐含重新分配内存的操作。
切片
type SliceHeader struct {
	Data uintptr
	Len int
	Cap int//元素个数,不是字节数 
}
  • 即使容量足够,依然需要用append()函数的返回值来更新切片本身,因为新切片的长度已经发生了变化。
// 可以在切片的开头添加元素
// 在开头一般会导致内存的重新分配,而且会导致已有的元素全部复制一遍,性能比较差
a = append([]int{0},a...)
  • 在判断一个切面是否为空时,一般通过len获取切片长度来判断,而很少用切片和nil直接做比较
避免切片内存泄漏问题
  • 底层的数组会被保存在内存中,直到它不再被引用为止,但是有的时候可能会因为一个小的内存的引用而导致底层整个数组处于被使用的状态,这会延迟垃圾回收器对底层数组的回收。
// 一个小的内存导致整个文件内容被引用
func FindPhoneNumber(filename string) []byte {
	b, _ := ioutil.ReadFile(filename)
	return regexp.MustCompile("[0-9]+").Find(b)
}
  • 要解决这个问题,可以将感兴趣的数据复制到一个新的切片中(虽然传值有一定的代价,但是换取的好处是切断了对原始数据的依赖)
func FindPhoneNumber(filename string) []byte {
	b, _ := ioutil.ReadFile(filename)
	b = regexp.MustCompile("[0-9]+").Find(b)
	return append([]byte{}, b...)
} 
  • 假设切片里存放的是指针对象,那么删除元素后,被删除的元素依然被切片底层数据引用,从而导致不能及时被垃圾回收器回收
var a []*int{ ... }
a = a[:len(a)-1] // 被删除的最后一个元素依然被引用,可能导致垃圾回收器操作被阻碍
  • 保险的方式是先将指向需要提前回收内存的指针设置为nil,保证垃圾回收器可以发现需要回收的对象,然后再进行切片删除操作。
var a[]*int{...}
a[len(a)-1] = nil
a = a[:len(a)- 1]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值