切片和数组的区别
1:切片是引用类型,数组是值类型
2:切片可以用make关键字创建
package main
import "fmt"
func main() {
slice_4 := make([]int, 5, 9)
// len=5, cap=9, slice=[0 0 0 0 0]
fmt.Printf("len=%d, cap=%d, slice=%v\n", len(slice_4), cap(slice_4), slice_4)
}
3:数组的大小必须在创建时就声明,切片不需要,切片会在容量不够时自动扩容,每次扩容是当前容量的2倍
a := [5]int{1, 2, 3, 4, 5} // 声明一个包含5个整数的数组
b := []int{1, 2, 3, 4, 5} // 声明一个包含5个整数的切片
// 个人理解就是在写[]int{}时,如果[]里写了数字,那就是数组,不写就是切片
c := [...]int{1, 2, 3, 4, 5}
// 这种写法看似也没有声明长度,其实编译器编译后等同于 =》 c := [5]int{1, 2, 3, 4, 5}
// 所以这种还是数组,值传递
指针类型,引用类型,值类型
- 值类型:基本数据类型和结构体都是值类型。变量的值直接存储在变量本身的内存空间中,而不是通过指针或引用来访问。在函数中传递时,实际传递的是值的副本,因此无法直接修改值类型本身,如果想要在函数中修改值类型,则需要获取到值类型的指针。示例代码,add就是值传递,add2就是指针传递
package main
import "fmt"
func main() {
// 定义一个int类型变量 num
var num = 1
fmt.Println("num = ", num) // num = 1
add(num)
fmt.Println("add之后,num = ", num) // add之后,num = 1
add2(&num)
fmt.Println("add2之后,num = ", num) // add之后,num = 2
}
func add(num int) {
num++
}
func add2(num *int) {
*num++
}
-
指针类型:它保存了一个变量在内存中的地址,可以通过指针去访问变量的值,或者修改变量的值。通常是值类型会转成指针类型去直接操作值类型变量的值。
-
引用类型:引用类型在内部使用指针来实现,它的值是一个指向底层数据结构的指针。因此再进行赋值或者函数传递时,实际上是传递了一个指向底层数据结构的指针,因此可以直接来操作数据。
不同协程之间是无法捕获彼异常的
package main
import (
"fmt"
"time"
)
func GoA() {
defer func() {
if err := recover(); err != nil {
fmt.Println("GoA panic:" + fmt.Sprintf("%s", err))
}
}()
go GoB()
}
func GoB() {
panic("GoB:error")
}
func main() {
go GoA()
time.Sleep(1 * time.Second)
fmt.Println("main")
}
打印:
panic: GoB:error
在GoA
函数中创建了一个协程GoB
,并且在GoB
协程中发生了异常,那么GoA
函数中的defer
和recover
是无法捕获这个异常的,因为GoB
协程是在另外一个独立的调用栈中运行的。