GO函数内部程序执行顺序

GO函数内部程序执行顺序,第1张

目录

GO

标准库

程序执行顺序


GO 包

包是结构化代码的一种方式:每个程序都由包(通常简称为pkg)的概念组成,可以使用自身的包或者从其它包中 导入内容。 如同其它一些编程语 言中的类库或命名空间的概念,每个Go文件都属于且仅属于一个包。一个包可以由许多以.go为扩展名的源文件组成,因此文件名和包名-般来说都是不相同的。 必须在源文件中非注释的第一行指明这个文件属于哪个包,如: package main。 package main表示-个可独立 执行的程序,每个Go应用程序都包含-个名为main的包。 一个应用程序可以包含不同的包,而且即使只使用main包也不必把所有的代码都写在一个巨大的文件里: 可以用一些较小的文件, 并且在每个文件非注释的第一行都使用 package main 来指明这些文件都属于main包。如果打算编译包名不是为main的源文件,如pack1 ,编译后产生的对象文件将会是pack1.a而不是可执行程序。另外要注意的是,所有的包名都应该使用小写字母。

标准库

标准库API:Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国https://studygolang.com/pkgdoc

在Go的安装文件里包含了一些可以直接使用的包,即标准库。在Windows下,标准库的位置在Go根目录下的子目录pkg\windows_amd64 中;在Linux下,标准库在Go根日录下的子目录pkg\linux_ amd64 中(如果是安装的是32位,则在linux_386目录中)。-般情况下,标准包会存放在G00S_ $GOARCH/ 目录下

Go的标准库包含了大量的包(如: fmt 和os),但是也可以创建自己的包。 如果想要构建一个程序, 则包和包内的文件都必须以正确的顺序进行编译。包的依赖关系决定了其构建顺序。 属于同一个包的源文件必须全部被一起编译,一个包即是编译时的一个单元,因此根据惯例,每个目录都只包含一个包。 如果对一个包进行更改或重新编译,所有引用了这个包的客户端程序都必须全部重新编译。 Go中的包模型采用了显式依赖关系的机制来达到快速编译的目的,编译器会从后缀名为.o的对象文件(需要且 只需要这个文件)中提取传递依赖类型的信息。

如果A.go依赖B.go, 而B.go 依赖C.go : ●编译C.go, B.go.然后是A.go. ●为了编译A. go,编译器读取的是B.go而不是C.go. 这种机制对于编译大型的项目时可以显著地提升编译速度。 示例:

一个程序包含两个包: cat和main, 其中cat包中包含两个变量Name和Age,请问main包中如何访问Name和 Age.

每个源文件都可以包含一个init函数,这个init函数自动被go框架调用。

cat.go

package cat
​
import "fmt"
​
var Name string = "tom"
var Age int = 5
​
//初始函数
func init() {
    fmt.Println("this is cat package")
    fmt.Println("修改前init函数:", Name, Age)
    Name = "jake"
    Age = 3
    fmt.Println("修改后init函数:", Name, Age)
}

main.go

package main
​
import (
    "dev_code/day9/example1/cat"
    "fmt"
)
//调用其他包,程序加载顺序
//cat. go中的全局变量---->cat. go中的init()函数_------->main. go中的main( )函数
​
func main() {
    fmt.Println("猫的名字:", cat.Name)
    fmt.Println("猫的年龄:", cat.Age)
}
[Running] go run "f:\goProject\src\dev_code\day9\example1\main\main.go"
this is cat package
修改前init函数: tom 5   //先加载的是cat包的全局变量,然后执行cat包中的init函数
修改后init函数: jake 3
猫的名字: jake     //最后执行的是main函数
猫的年龄: 3
​
[Done] exited with code=0 in 0.586 seconds

每一段代码只会被编译一次

一个Go程序是通过import 关键字将一组包链接在一起。 import "fmt" 告诉Go编译器这个程序需要使用fmt 包(的函数,或其他元素),fmt 包实现了格式化10 (输 入/输出)的函数。包名被封闭在半角双引号”” 中。如果打算从已编译的包中导入并加载公开声明的方法,不需 要插入已编译包的源代码。

当导入多个包时,导入的顺序会按照字母排序。

如果包名不是以口或1开头,如"fmt" 或者"container/list", 则Go会在全局文件进行查找;如果包名以 .7开头,则Go会在相对目录中查找;如果包名以1开头(在Windows下也可以这样使用),则会在系统的 绝对路径中查找。 导入包即等同于包含了这个包的所有的代码对象。 除了符号日 ,包中所有代码对象的标识符必须是唯一的, 以避免名称冲突。但是相同的标识符可以在不同的包中使用,因为可以使用包名来区分它们。 包通过下面这个被编译器强制执行的规则来决定是否将自身的代码对象暴露给外部文件:

可见性规则 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如: Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的public) ;标识符如果以小写字母开头则对包外是不可见的,但是他们在整个包的内部是可见并且 可用的(像面向对象语言中的private )。 因此,在导入一个外部包后,能够且只能够访问该包中导出的对象。 假设在包pack1中我们有一个变量或函数叫做 Thing (以T开头,所以它能够被导出),那么在当前包中导入 pack1包,Thing 就可以像面向对象语言那样使用点标记来调用: pack1. Thing (pack1 在这里是不可以省略 的)。因此包也可以作为命名空间使用,帮助避免命名冲突(名称冲突) :两个包中的同名变量的区别在于他们的包名, 例如pack1 . Thing和pack2. Thing。 可以通过使用包的别名来解决包名之间的名称冲突。 包的别名来访问包中函数

package main
//包的别名定义
import (
    a "dev_code/day9/example1/cat"  //a为别名
    b "fmt"                         //b为别名
)
​
//调用其他包,程序加载顺序
//cat. go中的全局变量---->cat. go中的init()函数_------->main. go中的main( )函数
​
func main() {
    b.Println("猫的名字:", a.Name)  //调用的时候也可以用别名
    b.Println("猫的年龄:", a.Age)
}

每个源文件都可以包含一个init函数,这个init函数自动被go框架调用。

总结:系统在执行代码的时候加载顺序:全局变---it函要数--->main函数 注意事项 如果导入了一个包却没有使用它,则会在构建程序时引发错误,如imported and not used: os ,这正是遵循了 Go的格言:“没有不必要的代码! "。

程序执行顺序

Go程序的执行(程序启动)顺序如下: 1.按顺序导入所有被main包引用的其包,然后在每个包中执行如下流程: 2.如果该包又导入了其它的包,则从第一步开始递归执行,但是每个包只会被导入一次。 3.然后以相反的顺序在每个包中初始化常量和变量,如果该包含有init函数的话,则调用该函数。 4.在完成这一切之后, main也执行同样的过程,最后调用main函数开始执行程序。 示例:

demo.go

package demo
​
import "fmt"
​
var Name string = "this is demo package"
var Age int = 20
​
func init() {
    fmt.Println("this is demo init()")
    fmt.Println("demo.package.Name=", Name)
    fmt.Println("demo.package.Age=", Age)
    Name = "this is demo new"
    Age = 200
    fmt.Println("demo.package.Name=", Name)
    fmt.Println("demo.package.Age=", Age)
}

test.go

package test
​
import (
    _ "dev_code/day9/example2/demo" //只会初始化。空白标识符,不调用包内的变量和函数
    "fmt"
)
​
var Name string = "this is test package"
var Age int = 10
​
func init() {
    fmt.Println("this is test init()")
    fmt.Println("test.package.Name=", Name)
    fmt.Println("test.package.Age=", Age)
    Name = "this is test new"
    Age = 100
    fmt.Println("test.package.Name=", Name)
    fmt.Println("test.package.Age=", Age)
}

main.go

package main
​
import (
    "dev_code/day9/example2/test"
    "fmt"
)
​
func main() {
    //main ---->test---->demo
    fmt.Println("main.package:", test.Name)
    fmt.Println("main.package:", test.Age)
}

输出

[Running] go run "f:\goProject\src\dev_code\day9\example2\main\main.go"
this is demo init()
demo.package.Name= this is demo package
demo.package.Age= 20
demo.package.Name= this is demo new
demo.package.Age= 200
this is test init()
test.package.Name= this is test package
test.package.Age= 10
test.package.Name= this is test new
test.package.Age= 100
main.package: this is test new
main.package: 100
​
[Done] exited with code=0 in 0.602 seconds

流程图:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/990667.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存