分类 Golang 下的文章

Golang进阶-init()初始化

1.init()、main()是go语言中的保留函数;init()函数用于初始化信息,main()函数用于程序执行的入口

2.相同点

  • 两个函数在定义时不能有任何的返回值和参数
  • 该函数只能由go程序自动调用,不可以被引用

3.不同点

  • init可以应用于任何包中,且可以重复定义多个
  • main函数只能用于main包中,且只能定义一个

4.两个函数的执行顺序

  • 同一个go文件中的init()调用顺序是从上到下
func init() {
    fmt.Println("第一个init()函数")
}
func init() {
    fmt.Println("第二个init()函数")
}
结果:
untils包下的until.go文件下第一个init()函数
untils包下的until.go文件下第二个init()函数
  • 同一个package包中的不同文件,将文件名按字符串进行 “从小到大”排序,之后顺序调用个文件中的init()函数
untils包下的test1.go文件中的init()函数。。。
untils包下的until.go文件下第一个init()函数
untils包下的until.go文件下第二个init()函数
  • 不同的package包,如果不互相依赖的话,按照import的顺序调用init()函数
import (
    "Go_Advanced/pk1"
    "Go_Advanced/utils"
)
结果:
pk1包下的init()函数
untils包下的test1.go文件中的init()函数。。。
untils包下的until.go文件下第一个init()函数
untils包下的until.go文件下第二个init()函数
untils包下的until.go文件下count()函数
pk1包下的MyTest1函数
  • 如果pakage存在依赖,调用顺序为最后被依赖的最先被初始化;例如导入顺序 main->A->B->C, 则初始化顺序为 C->B->A->main

Golang进阶-包的使用

1:包其实就是目录,不同的包相当于不同的目录;每个包下是具有相同属性的文件:类似MVC目录的作用

2:src目录是以代码包的形式组织并保存Go源文件的;每个项目的main包下的是入口main函数

3:定义包的规则和要求:package 包名

  • 一个目录下的所有文件归属一个包,package的声明要一致;可以不一致,但习惯上还是要写一致
  • 包可以嵌套
  • 同包下的函数不需要导入包,可以直接使用
  • main包,main函数所在的包,其它的包不能使用mian包名
  • 导入包的时候,路径要从src下开始写;可以写成绝对路径和相对路径

4:特殊的一些import方式

  • 点操作: 例如:import( . "fmt") 含义:导入这个包后,调用这个包的函数时,可以省略前缀的包名;fmt.Plintln("hello world") => Println("hello world")
  • 起别名:import( p1 "package1") p1.Method()
  • _ 操作:如果仅仅导入包时执行初始化操作,并不需要使用包内的其他函数,常量等资源;只是执行了这包内的init函数,不会调用其他函数
  • 对于import要导入的外部包,可以使用go get命令获取下来放到GOPATH对应的目录中
示例:mysql
1>go get github.com/go-sql-driver/mysql

2>链接
db, err := sql.Open("mysql", "admin:admin@tcp(127.0.0.1:3306)/test?charset=utf8")
if err != nil {
    fmt.Println("错误信息:", err)
    return
}
fmt.Println("链接成功:", db)

Golang错误机制初识

Go语言-defer语句

  • 位置:仅能在函数和方法中
  • 构成:关键字和一个表达式语句(表达式不能是内建函数和unsafe中的函数)
  • 作用:最后执行;保护措施;节约资源
func readFile(path string) ([]byte, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()
    return ioutil.ReadAll(file)
}
  • 注意:当有多个defer时,执行顺序为倒序
func deferIt() {
    defer func() {
        fmt.Print(1)
    }()
    defer func() {
        fmt.Print(2)
    }()
    defer func() {
        fmt.Print(3)
    }()
    fmt.Print(4)
}

输出:4321
  • 特别提示1:有参数传入,比如:fmt.Print(i + 1)。如果代表传入参数的是一个表达式,那么在defer语句被执行的时候该表达式就会被求值了
func deferIt3() {
    f := func(i int) int {
        fmt.Printf("%d ",i)
        return i * 10
    }
    for i := 1; i < 5; i++ {
        defer fmt.Printf("%d ", f(i))
    }
}
打印出1 2 3 4 40 30 20 10
  • 特别提示2:defer携带的表达式语句代表的是对匿名函数的调用(注意外部变量传递)
func deferIt4() {
    for i := 1; i < 5; i++ {
        defer func() {
            fmt.Print(i)
        }()
    }
}
打印出5555

func deferIt4() {
    for i := 1; i < 5; i++ {
        defer func(n int) {
            fmt.Print(n)
        }(i)
    }
}
打印出1234

Go语言异常处理——error

  • 处理错误的惯用法之一:Go函数可以一次返回多个结果(怎样在传递错误)
func readFile(path string) ([]byte, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()
    return ioutil.ReadAll(file)
}
函数readFile有两个结果声明。第二个结果声明的类型是error。error是Go语言内置的一个接口类型
type error interface { 
    Error() string
}
  • 怎样创造错误:调用标准库代码包errors的New函数即可
if path == "" {
    return nil, errors.New("The parameter is invalid!")
}

Go语言异常处理——panic

  • 可被意译为运行时恐慌,只有在程序运行的时候才会被“抛出来” == 程序崩溃
  • 恐慌是会被扩散的,它会被迅速地向调用栈的上层传递。如果我们不显式地处理它的话,程序的运行瞬间就会被终止。
  • 人为地产生一个运行时恐慌,可以被恢复的;内建函数recover
  • 内建函数panic和recover是天生的一对。前者用于产生运行时恐慌,而后者用于“恢复”它
  • recover函数必须要在defer语句中调用才有效,因为一旦有运行时恐慌发生,当前函数以及在调用栈上的所有代码都是失去对流程的控制权
  • 只有defer语句携带的函数中的代码才可能在运行时恐慌迅速向调用栈上层蔓延时“拦截到”它
defer func() {
    if p := recover(); p != nil {
        fmt.Printf("Fatal error: %s\n", p)
    }
}()
调用了recover函数。该函数会返回一个interface{}类型的值;interface{}代表空接口。Go语言中的任何类型都是它的实现类型。