#### 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. JAVA判断指定url地址是否匹配指定url集合中的任意一个

    判断字符串为空和判断集合是否为空用到依赖,也可以改成自己的方式 <!-- Spring Web --> <dependency> <groupId>org.spri ...

  2. SpringBoot整合websocket简单示例

    依赖 <!-- springboot整合websocket --> <dependency> <groupId>org.springframework.boot&l ...

  3. cmake之譬判断cmake的版本

    note 有时候,可能使用的cmake语法 与cmake的版本有关系, 比如modern cmake. 这时候我们可以在 CMAKELISTS.TXT中 判断 cmakeLists.txt 代码 if ...

  4. 【LeetCode】1051. Height Checker 解题报告(Python & C++)

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

  5. Log4自定义Appender介绍

    最初想要在执行一段业务逻辑的时候调用一个外部接口记录审计信息,一直找不到一个比较优雅的方式,经过讨论觉得log4j自定义的appender或许可以实现此功能.后来就了解了一下log4j的这部分. Ap ...

  6. Consistency Regularization for GANs

    目录 概 主要内容 Zhang H., Zhang Z., Odena A. and Lee H. CONSISTENCY REGULARIZATION FOR GENERATIVE ADVERSAR ...

  7. matplotlib 高阶之path tutorial

    目录 Bezier example 用path来画柱状图 随便玩玩 import matplotlib.pyplot as plt from matplotlib.path import Path i ...

  8. Mysql数据库服务端的安装

    一般提到Mysql数据库的安装在工作当中是说的安装数据库管理软件的服务端,服务端的安装可以安装在Windows环境,也可以安装在Linux环境. Windows环境安装:目前安装比较流行的是5.7,增 ...

  9. Golang项目的配置管理——Viper简易入门配置

    Golang项目的配置管理--Viper简易入门配置 What is Viper? From:https://github.com/spf13/viper Viper is a complete co ...

  10. Java初学者作业——编写Java程序,输入一个数字,实现该数字阶乘的计算。

    返回本章节 返回作业目录 需求说明: 编写Java程序,输入一个数字,实现该数字阶乘的计算.一个数字的阶乘是所有小于及等于该数的正整数的积,自然数n的阶乘写作n! .例如,5的阶乘等于1*2*3*4* ...