#### Go 函数,包(二)
***百丈峰,松如浪,地势坤,厚德载物之像***
今天又到周五啦,你们有没有激动呢,反正我很激动,又有两天的自由了;
上一节我们学习了Go 的函数和包的一些知识 , 今天接着学习...
---
##### init 函数
每个程序源文件都可以包含一个init 函数, 该函数在main 函数前执行,被Go 运行框架调用;
package main

import "fmt"

func init(){
fmt.Print("init ")
}
func main() {
fmt.Print("main")
}

  


输出结果: init main
init 函数的注意事项和细节:
1. 如果一个文件同时包含***全局变量定义,init函数和main 函数***则执行的流程为全局变量定义->init函数->main函数;
2. 其主要作用是完成一些初始化工作
3. 如果多个包都有init 函数时,执行顺序为导入顺序,如:
A 导入了 B , B 导入了 C , 那么执行顺序为先执行C 中的全局变量定义,init 函数,再执行B 包中的, 最后执行A 包中的;
package main

import "fmt"
var a = test01()
func init(){
fmt.Println("init") // 执行顺序2
fmt.Println(a) // 执行顺序3
}
func test01() int {
fmt.Println("test01") // 执行顺序1
return 1
}
func main() {
fmt.Println("main") // 执行顺序4
}

  


---
##### 匿名函数
Go 支持匿名函数,匿名函数也就是没有名字的函数,如果某一个函数希望使用一次,可以使用匿名函数,同时匿名函数也可以实现多次调用;
如果将匿名函数赋值给一个全局变量,那么这个匿名函数就成为了一个全局匿名函数,在程序的有效作用域都有效;

package main

import "fmt"

func main(){
// 定义时直接调用
sum := func(a,b int) int {
return a +b
}(10,20)
fmt.Println(sum)
// 将匿名函数赋值给一个变量,通过变量调用匿名函数
a := func(a,b int) int {
return a+b
}
sum = a(10,20)
fmt.Println(sum)
}

  


---
##### 闭包
闭包实际上就是一个函数和与其相关的引用环境组合的一个整体
package main

import "fmt"

func add()func(int)int{
var n int = 1
return func(i int) int {
n += i
return n
}
}
func main(){
a := add()
fmt.Println(a(1)) // 2
fmt.Println(a(10)) //12
fmt.Println(a(2)) //14
}

  


说明:
1. add 是一个函数,返回的数据类型是一个匿名函数;
2. 返回的匿名函数 引用到add 函数的变量n ,因此返回的匿名函数就和n 形成一个整体,构成闭包;
3. 也可以这样理解: 闭包是类,函数是方法,n 是字段,函数和它使用的n 构成闭包;
4. 因此当反复调用a 函数时, n 将累计;
package main

import (
"fmt"
"strings"
) func addStr() func(str string) string {
var base = "a"
return func(str string) string {
base += str
return base
}
}
// 判断字符串的后缀是否为指定的
func makeSuffix(suffix string) func(string) string {
return func(s string) string {
if !strings.HasSuffix(s,suffix) {
return s + suffix
}
return s
}
}
func main(){
a := addStr()
fmt.Println(a("b")) // ab
fmt.Println(a("c")) // abc
fmt.Println(a("d")) // abcd
jpg := makeSuffix(".jpg")
png := makeSuffix(".png")
fmt.Println(jpg("a.jpg")) // a.jpg
fmt.Println(jpg("b")) //b.jpg
fmt.Println(png("a.png")) // a.png
fmt.Println(png("b")) //b.png
}

  


1. 返回的匿名函数和参数suffix 变量组合成一个闭包,因此传入一次可以多次调用;
---
##### defer 函数
defer 也称为延时执行;
当函数执行到defer 时,暂时不执行,将defer 后的语句压入独立的栈,当函数执行完毕,return 前,再从defer 栈按照先入后出原则方式执行;
package main

import "fmt"

func add(a,b int) int {
defer fmt.Println("a=",a) //10 输出顺序3 , 在将语句放入栈时,相关参数的值会进行拷贝
defer fmt.Println("b=",b) //20 输出顺序2 , 在将语句放入栈时,相关参数的值会进行拷贝
a = 11
sum := a + b
defer fmt.Println("sum=",sum) //31 输出顺序1
return sum
}
func main(){
sum := add(10,20)
fmt.Println(sum) //31 输出顺序4
}

  


***在defer 将语句入到栈时,会将相关参数的值进行拷贝***
1. 在Go 开发中通常会在创建资源(打开文件,连接数据库,锁资源)后使用defer file.Close() conn.Close()
2. 在defer 后,仍可以继续使用已经创建的资源;
---
##### 函数参数传递方式
上一节中已经讲过函数参数的值类型与引用类型,我们再来深入总结一下,这个知识点在编译型语言中很重要;
1. 函数参数是值类型时就是值传递,函数参数是引用类型就是引用传递;
2. 不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是值传递是值的拷贝,引用传递是地址的拷贝;
3. 一般情况下地址拷贝效率高,而值拷贝由参数的数据大小, 数据越大,效率越低;
4. 值类型: 基本数据类型int 系列, float 系列, bool, string, 数组,结构体;
5. 引用类型: 指针,slice 切片, map , chan ,interface ;
package main

import "fmt"

// 值传递
func test01(a int){
fmt.Printf("[test01] a value= %d a address=%p\n",a,&a)
}
// 对于值传递希望更改原来的值可以传入变量地址
func test03(a *int){
*a = 100
fmt.Printf("[test03] c value=%v c address=%p\n",*a,&a)
}
// 引用传递
func test02(a []int){
fmt.Printf("[test02] b value=%v b address=%p\n",a,&a)
}
func main(){
var a int = 10
fmt.Printf("a value= %d a address=%p\n",a,&a)
test01(a)
var b = []int{1,2}
fmt.Printf("b value=%v b address=%p\n",b,&b)
test02(b)
var c = 10
test03(&c)
fmt.Printf("c value=%v c address=%p\n",c,&c)
}

  


---
##### 变量的作用域
1. 函数内部声明或定义的变量是局部变量,作用域限于函数内部;
2. 函数外部声明或定义的变量是全局变量,作用域在整个包有效,若首字母大写,则作用域为整个程序;
3. 如果变量声明或定义在代码块内,如: if/for 代码块内,则作用域仅限于代码块;
package main

import "fmt"

// 全局变量
var name = "golang"
// 如果首字母大写,则在整个程序中有效,其它包也可以使用
var Age = 22 func test01(){
// 局部变量
var a int = 10
fmt.Println(a)
// 使用全局变量
fmt.Println(name)
if a > 2 {
// 代码块内部的局部变量, 仅限于if 代码块有效
var d int = 100
fmt.Println(d)
}
// 代码块内部的局部变量, 仅限于if 代码块有效
//fmt.Println(d) // error
}
func main(){
// 局部变量
var b int = 1
fmt.Println(b)
// 使用全局变量
fmt.Println(name)
test01()
}

  个人微信公众号上有最新文章: 欢迎大家关注一同学习交流

Go 函数,包(二)的更多相关文章

  1. Jquery--JS的函数包

    Jquery-----JS的函数包,直接来调用方法. 一.基本知识 用法:把jquery-1.7.2.js直接复制到要做的网站项目中,拖拽引用和JS用法一样. 二.选择器 [1]基本: 1.取ID:v ...

  2. ioutil包二

    ioutil包二 (原创随笔,转载请注明出处 http://www.cnblogs.com/majianguo/p/8016426.html) ioutil包实现了一些I/O实用功能,导出了7个函数和 ...

  3. R语言实现SOM(自组织映射)模型(三个函数包+代码)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- SOM自组织映射神经网络模型 的R语言实现 笔 ...

  4. Go-数据类型以及变量,常量,函数,包的使用

    Go-数据类型以及变量,常量,函数,包的使用 一.数据类型 1.字符串类型 string -双引号包裹的:"xxx" -反引号包裹,可以换行, 注意: 区别于python,是没有单 ...

  5. Javascript常用方法函数收集(二)

    Javascript常用方法函数收集(二) 31.判断是否Touch屏幕 function isTouchScreen(){ return (('ontouchstart' in window) || ...

  6. Lua函数之二

    Lua函数之二 Lua中函数的两个重要特性: 1.函数和其他类型(如number.string)一样,可以存放在变量中,也可以存放在table中,可以作为函数的参数,还可以作为函数的返回值. 2.嵌套 ...

  7. 编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异

    编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异 题目挺绕口的.C++ 11的好东西不算太多,但变参模板(Variadic Template)肯定是其中耀眼的一 ...

  8. 我的第一个python web开发框架(10)——工具函数包说明(一)

    PS:原先是想直接进入功能开发,要用到什么函数时再创建,这样也容易熟悉每个函数的由来和使用方法,但考虑到这样操作,到时会经常在不同文件间切换,不好描述,容易造成混乱,所以还是使用函数库这种方式来说明. ...

  9. day 16 - 2 内置函数(二)练习

    内置函数(二)练习 1.用 map 来处理字符串列表,把列表中所有人都变成 sb,比方 alex_sbname=['alex','wupeiqi','yuanhao','nezha'] name=[' ...

随机推荐

  1. 【LeetCode】1417. 重新格式化字符串 Reformat The String

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 栈 日期 题目地址:https://leetcode- ...

  2. 【九度OJ】题目1431:Sort 解题报告

    [九度OJ]题目1431:Sort 解题报告 标签(空格分隔): 九度OJ [LeetCode] http://ac.jobdu.com/problem.php?pid=1431 题目描述: 给你n个 ...

  3. 【LeetCode】974. Subarray Sums Divisible by K 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划 前缀和求余 日期 题目地址:https:/ ...

  4. 【LeetCode】50. Pow(x, n) 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述: 题目大意 解题方法 递归 迭代 日期 题目地址: https://le ...

  5. 【LeetCode】899. Orderly Queue 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/orderly- ...

  6. 1678 lyk与gcd

    1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将  ai 改为b.2:给定一个数i,求所有 ...

  7. How many integers can you find(hdu1796)

    How many integers can you find Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  8. RTD2172替代方案|TYPEC转HDMI4K@60HZ拓展坞|CS5265替代RTD2172

    瑞昱RTD2172是TYPEC转HDMI4K60HZ音视频数据转换器芯片.CS5265可以替代兼容RTD2172,除了实现同等的转换功能外且整体方案成本和性价比方面比RTD2172要高,且外围器件较少 ...

  9. Java网络编程Demo,使用TCP 实现简单群聊功能Groupchat,创建一个服务端,使多个客户端都能收到消息

    效果图: 开启服务端 客户端一 客户端二 客户端三 实现代码: 客户端类 import java.io.IOException; import java.net.ServerSocket; impor ...

  10. css基础-1

    css简介 一.CSS 指层叠样式表 样式定义如何显示 HTML 元素 样式通常存储在样式表中 把样式添加到 HTML 4.0 中,是为了解决内容与表现分离的问题 外部样式表可以极大提高工作效率 外部 ...