Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Golang int函数教程

Golang int函数使用实例全面教程

作者:帽儿山的枪手

这篇文章主要为大家介绍了Golang int函数使用实例全面教程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

init 函数

例如某些场景下,我们需要提前初始化一些变量或逻辑代码。在这种情况下,我们可以用一个特殊的init初始化函数来简化初始化工作,每个文件都可以包含一个或多个init初始化函数。

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

init初始化函数除了不能被调用或引用外,其他行为和普通函数类似。在每个文件中的init初始化函数,在程序开始执行时按照它们声明的顺序被自动调用。

init函数先于main函数执行

注意:每个包在解决依赖的前提下,以导入声明的顺序初始化,每个包只会被初始化一次。因此,如果一个p包导入了q包,那么在p包初始化的时候可以认为q包必然已经初始化过了。

init函数的特征

初始化的过程

runtime是go语言运行所需要的基础设施,也是go的核心特性。 该内容将放到后续《go基础之特性》章节为大家分享。

使用案例:init初始化顺序

package main
import "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 main
import (
    "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 main
import "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 main
import "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.go
call a() in a.go
call b() in b.go
init in main.go
init in a.go
init in b.go
main()

结论,同一个包不同源文件的init函数执行顺序,golang 没做官方说明。这块加载过程是按照 go run 文件排序。

使用案例:多个init函数初始化顺序

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

输出

init 1
init 2
main

结论:init函数比较特殊,可以在包里被多次定义。

方法

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

定义说明

一个方法就是一个包含了接受者的函数, 接受者可以是命名类型或者结构体类型的一个值或者是一个指针。

方法定义

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

使用

定义一个结构类型和该类型的一个方法

package main
import "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 main
import "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 main
import "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。

以上就是Golang int函数使用实例全面教程的详细内容,更多关于Golang int函数教程的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文