Panic 和 Fatal #
Fatal #
执行log.Fatal程序直接退出,不会执行其它任何defer
#源码
func Fatal(v ...interface{}) {
std.Output(2, fmt.Sprint(v...))
os.Exit(1)
}
//说明:直接屏幕输出,退出程序直接exit了
#测试代码
func main() {
fmt.Println("main 1111")
defer fmt.Println("main defer 22222")
test1()
}
func test1() {
fmt.Println("test 1111")
defer fmt.Println("test derfer 22222")
log.Fatal("test 3333333")
}
#output
main 1111
test 1111
2022/03/07 23:37:09 test 3333333
panic #
类似其它语言的异常exception,执行后会执行defer,同时也可以通过recover捕获唤醒
func main() {
fmt.Println("main 1111")
defer func() {
fmt.Println("main defer 22222")
if err := recover(); err != nil {
fmt.Println("main recover",err)
}
}()
test1()
}
func test1() {
fmt.Println("test 1111")
defer func() {
fmt.Println("test derfer 22222")
//if err := recover(); err != nil {
// fmt.Println("test recover",err)
//}
}()
log.Panic("test 3333333")
}
#output
1、main 1111
2、test 1111
3、2022/03/07 23:41:48 test 3333333
4、test derfer 22222
#如果test中recover去掉注释,会执行5,不会执行7
5、test recover test 3333333
6、main defer 22222
#注释掉test中recover代码,不执行5执行7
7、main recover test 3333333
new和make #
new #
我们一般通过var声明变量,变量未初始化,这些变量未分配内存地址
var i int
var s string
var i1 *int
下面代码会报错
func main() {
var i *int
*i=10
fmt.Println(*i)
}
panic: runtime error: invalid memory address or nil pointer dereference
于引用类型的变量,我们不光要声明它,还要为它分配内容空间,否则我们的值放在哪里去呢?所以指针、切片、数组、通道(chan)都需要初始化并分配内存地址
func main() {
var i *int
i=new(int)
*i=10
fmt.Println(*i)
}
#output
10
type user struct {
Name string
Lock sync.Mutex
}
func main() {
u := new(user)
fmt.Printf("%+v",u)
}
#output
&{Name: Lock:{state:0 sema:0}}
不用初始化,自动分配各类型的默认值
new它返回的永远是类型的指针,指向分配类型的内存地址
make #
make也是用于内存分配的,但是和new不同,它只用于chan、map以及切片的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
func make(t Type, size …IntegerType) Type
从函数声明中可以看到,返回的还是该类型。
二者异同
所以从这里可以看的很明白了,二者都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);而new用于类型的内存分配,并且内存置为零。所以在我们编写程序的时候,就可以根据自己的需要很好的选择了。
make返回的还是这三个引用类型本身;而new返回的是指向类型的指针。
其实new不常用
所以有new这个内置函数,可以给我们分配一块内存让我们使用,但是现实的编码中,它是不常用的。我们通常都是采用短语句声明以及结构体的字面量达到我们的目的,比如:
`i:=0``u:=user{}`
这样更简洁方便,而且不会涉及到指针这种比麻烦的操作。
make函数是无可替代的,我们在使用slice、map以及channel的时候,还是要使用make进行初始化,然后才才可以对他们进行操作
iota #
iota是golang语言的常量计数器 ,只能在常量表达中使用
type pow int
type control byte
const (
ONE pow = 1 << iota
TWO
THREE
FOUR
L control = 37 + iota
U
R
D
)
func main() {
fmt.Println(ONE,TWO,THREE,FOUR)
fmt.Println(L,R,U,D)
}
#output
1 2 4 8
41 43 42 44