大家好,明天将梳理出的 Go语言函数用法内容,分享给大家。 请多多指教,谢谢。

本次《Go语言函数应用》内容共分为三个章节,本文为第三章节。

  • Golang 根底之函数应用 (一)
  • Golang 根底之函数应用 (二)
  • Golang 根底之函数应用 (三)

本章节内容

  • init 函数
  • 办法

init 函数

介绍

例如某些场景下,咱们须要提前初始化一些变量或逻辑代码。在这种状况下,咱们能够用一个非凡的init初始化函数来简化初始化工作,每个文件都能够蕴含一个或多个init初始化函数。

func init() {} // init()函数语法

init初始化函数除了不能被调用或援用外,其余行为和一般函数相似。在每个文件中的init初始化函数,在程序开始执行时依照它们申明的程序被主动调用。

init函数先于main函数执行

留神:每个包在解决依赖的前提下,以导入申明的程序初始化,每个包只会被初始化一次。因而,如果一个p包导入了q包,那么在p包初始化的时候能够认为q包必然曾经初始化过了。

init函数的特色

  • init函数是用于程序执行前做包的初始化的函数,比方初始化包里的变量等
  • init函数没有输出参数、返回值
  • 每个包能够领有多个init函数
  • 包的每个源文件也能够领有多个init函数
  • 同一个包中多个init函数的执行程序go语言没有明确的定义(阐明)
  • 不同包的init函数依照包导入的依赖关系决定该初始化函数的执行程序
  • init函数不能被其余函数调用,而是在main函数执行之前,主动被调用

初始化的过程

  1. 初始化导入的包(程序并不是按导入程序(从上到下)执行的,runtime须要解析包依赖关系,没有依赖的包最先初始化);
  2. 初始化包作用域的变量(并非依照“从上到下、从左到右”的程序,runtime解析变量依赖关系,没有依赖的变量最先初始化);
  3. 执行包的init函数;
runtime是go语言运行所须要的基础设施,也是go的外围个性。 该内容将放到后续《go根底之个性》章节为大家分享。

应用

案例:init初始化程序

package mainimport "fmt"var Num int = Call() // 全局变量申明func init() { // 初始化函数    fmt.Println("init()")}func Call() int {    fmt.Println("Call()")    return 1}func main() {    fmt.Println("main()")}

输入

Call()init()main()

论断,初始化的过程:Num变量初始化 -> init() -> main()

案例:同一个包不同源码的init初始化程序

首先创立3个文件, main.go代码中蕴含全局变量、init初始化函数定义,和main函数入口; a.go 和 b.go代码文件中,只蕴含全局变量、init初始化函数的定义。

main.go文件

package mainimport (    "fmt")var _ int = m()func init() {   fmt.Println("init in main.go")}func m() int {   fmt.Println("call m() in main.go")   return 1}func main() {   fmt.Println("main()")}

a.go 文件

package mainimport "fmt"var _ int = a()func init() {   fmt.Println("init in a.go")}func a() int {   fmt.Println("call a() in a.go")   return 1}

b.go 文件

package mainimport "fmt"var _ int = b()func init() {   fmt.Println("init in b.go")}func b() int {   fmt.Println("call b() in b.go")   return 1}
因为a.go 和 b.go 都归属于main包,但没有两文件中没有main函数入口。 在执行的时候,须要应用 go run main.go a.go b.go 这样模式执行,runtime会将所有文件进行加载初始化。

输入

call m() in main.gocall a() in a.gocall b() in b.goinit in main.goinit in a.goinit in b.gomain()

论断,同一个包不同源文件的init函数执行程序,golang 没做官网阐明。这块加载过程是依照 go run 文件排序。

案例:多个init函数初始化程序

package mainimport "fmt"func init() {   fmt.Println("init 1")}func init() {   fmt.Println("init 2")}func main() {   fmt.Println("main")}

输入

init 1init 2main

论断:init函数比拟非凡,能够在包里被屡次定义。

办法

介绍

Golang中办法,实现是以绑定对象实例, 并隐式将实例作为第一实参 (receiver)。

定义阐明

  • 只能为以后包内命名类型定义办法;
  • 参数 receiver 可任意命名,如办法中未曾应用,可省略参数名;
  • 参数 receiver 类型能够是 T 或 *T, 基类型 T 不能是接口或指针;
  • 不反对办法重载, receiver 只是参数签名的组成部分;
  • 可用实例 valuepointer 调用全副办法, 编译器主动转换

一个办法就是一个蕴含了接受者的函数, 接受者能够是命名类型或者构造体类型的一个值或者是一个指针。

办法定义

func (recevier type) methodName(参数列表) (返回值列表) {} // 参数和返回值能够省略

应用

定义一个构造类型和该类型的一个办法

package mainimport "fmt"// 构造体type Info struct {    Name  string    Desc string}// 办法func (u Info) Output() {    fmt.Printf("%v: %v \n", u.Name, u.Desc)}func main() {    // 值类型调用办法    u1 := Info{"帽儿山的枪手", "分享技术文章"}    u1.Output()    // 指针类型调用办法    u2 := Info{"帽儿山的枪手", "分享技术文章"}    u3 := &u2    u3.Output()}

输入

帽儿山的枪手: 分享技术文章 帽儿山的枪手: 分享技术文章

匿名办法

如类型S蕴含匿名字段 *T ,则 S 和 *S 办法集蕴含 T + *T 办法。

这条规定说的是当咱们嵌入一个类型的指针, 嵌入类型的接受者为值类型或指针类型的办法将被晋升, 能够被内部类型的值或者指针调用。
package mainimport "fmt"type S struct {    T}type T struct {    int}func (t T) testT() {    fmt.Println("如类型 S 蕴含匿名类型 *T, 则 S 和 *S 办法集蕴含 T 办法")}func (t *T) testP() {    fmt.Println("如类型 S 蕴含匿名字段 *T, 则 S 和 *S 办法汇合蕴含 *T 办法")}func main() {    s1 := S{T{1}}    s2 := &s1    fmt.Printf("s1 is : %v\n", s1)    s1.testT()    s1.testP() // 晋升指针类型调用    fmt.Printf("s2 is : %v\n", s2)    s2.testT() // 晋升值类型调用    s2.testP()}

输入

s1 is : {{1}}如类型 S 蕴含匿名类型 *T, 则 S 和 *S 办法集蕴含 T 办法如类型 S 蕴含匿名字段 *T, 则 S 和 *S 办法汇合蕴含 *T 办法s2 is : &{{1}}如类型 S 蕴含匿名类型 *T, 则 S 和 *S 办法集蕴含 T 办法如类型 S 蕴含匿名字段 *T, 则 S 和 *S 办法汇合蕴含 *T 办法

表达式

依据调用者不同,办法分为两种表现形式

instance.method(args...) ---> <type>.func(instance, args...)
前者称为 method value, 后者 method expression则须显式传参。
package mainimport "fmt"type User struct {    id   int    name string}func (self *User) Test() {    fmt.Printf("%p, %v\n", self, self)}func main() {    u := User{1, "帽儿山的枪手"}    u.Test()    mValue := u.Test    mValue() // 隐式传递 receiver    mExpression := (*User).Test    mExpression(&u) // 显式传递 receiver}

输入

0xc00000c018, &{1 帽儿山的枪手}0xc00000c018, &{1 帽儿山的枪手}0xc00000c018, &{1 帽儿山的枪手}

论断,办法是指针类型,method value 会复制 receiver。

技术文章继续更新,请大家多多关注呀~~

搜寻微信公众号【 帽儿山的枪手 】,关注我