Go语言学习笔记04--特殊函数&工程化结构&数组&随机数

栏目: Go · 发布时间: 7年前

1.匿名函数     go语言中的函数都是声明在函数之外的,并不存在函数内声明函数的问题     但是也会存在一些特殊情况,在这写情况中允许在函数内部去再次定义一个函数。     这种情况下,在函数内部定义的函数就必须遵守一些 go 语言定义的特殊规则。     而这些内部的函数,被统称为:匿名函数。         func main (){             func (..){..}         }     (1)对于go语言中的匿名函数而言,由于其不存在函数名,无法使用传统函数的调用功能         所以如何调用匿名函数就必须从两个角度出发来解决问题。                          1)利用函数指针,完成匿名函数的"重命名",然后再次调用                 func main(){                     fpointer := func (num int)int{                          return num+10;                     }                     fmt.Println(fpointer(100));                 }             利用函数指针的情况时需要注意,由于函数指针是在函数内部被定义的             所以函数指针其实是一个局部变量,因此函数指针是只能够在当前所在的函数内使用的             一旦超出当前所在函数范围,即宣告函数指针失效。             2)利用AIIFE,即Anonymous-Immediately-Invoked-Function-Expression               匿名立即自动执行的函数表达式,来完成匿名函数的调用                   func main(){                       func (num int){                           fmt.Println(num+100);                       }(35);                   }             这种方式虽然能够在“真正匿名”的情况下完成函数的调用,但是缺陷也相当明显。             那就是AIIFE只能在它声明的时候被立即调用一次,无法延迟调用,也无法多次重复调用。     (2)闭包         闭包是go语言中匿名函数的另外一种表现形式。         从概念上来说,闭包是一种:         使得函数外部可以间接访问函数内部定义的局部变量的手段,在go语言中经常表现为匿名函数的样子。             func createClousre() func()int{                 var num int = 100;                 //在这里闭包就是 返回的这个匿名函数                 return func ()int{                     return num;                 }             }         闭包在go语言中主要有两个作用:                          1)能够使得在函数外部访问到函数内部的局部变量,打破了“局部视障”                 func main(){                     clo := createClousre();                     fmt.Println(clo());//输出局部变量num的值 100                 }                 原本在createClousre函数中定义的局部变量num,在main函数中是不可能直接访问到的                 但是我们借助于闭包clo,完成了一次打破“局部视障”的操作             2)能够将局部变量的生命周期延长,具体延长时间视闭包存在的函数而定                 func main(){                     clo := createClousre();//createClousre函数在此执行结束                     fmt.Println(clo());                     }                 原本createClousre函数在调用完成后就会将其占有的内存销毁,                 即局部变量num也会跟随消失不见,再也无法访问。                 但是由于闭包中持有了局部变量num,于是闭包就将局部变量num的声明周期延长到了clo上                 所以变量clo只要还继续存在,那么局部变量num就得以继续被访问。 2.递归函数     go语言中的递归函数与传统 c语言 语法类似,只不过考虑到在go语言中很多运算符是不能直接与调用语句结合。     故而写法上可能存在一点点差异。     (1)递归函数:         递归函数是指在函数的内部,再次调用本身的函数。         eg:             func f(){                 ...                 f();             }         乍一看这样的写法似乎是一个错误的写法,会导致回调地狱的产生。         实际上递归只是结构上需要满足这样,而事实中递归函数的构成还需要三个要素。     (2)递归三要素:         递归变量赋初值、递归结束条件、递归变量向着递归结束的趋势发生变化         1)递归变量赋初值             指的是递归函数总是要有一个“标识”来提供作为判断递归结束的标准             并且这个“标识”是需要有一个初始值的。             eg:                 func f(num int){                     ...                     f(num);                 }                 此时形参num就可以充当递归函数的递归变量。         2)递归结束条件             指的是递归函数总是要有一个通过标识来进行的判断。             这个判断用于决定递归何时结束, 毕竟大家都不希望回调地狱的发生             eg:                 func f(num int){                     if num <= 1{                         return num;                     }                     f(num);                 }             此时针对递归变量的条件判断if就成为了递归结束条件,             只要一旦递归变量满足结束条件,那么递归函数就会立即结束。避免了回调地狱的发生。         3)递归变量向着递归结束的趋势发生变化             这一点非常关键,因为递归结束条件之所以能够触发,             是因为递归变量必须一直在发生变化,而变化就会有趋势             在递归函数中由于函数最终必须要执行结束,因此递归变量就必须向着递归结束的趋势发生变化             eg:                 func f(num int){                     if num <= 1{                         return num;                     }                     num --;                     f(num);                 }             这样一来,每次递归调用f()函数的时候,num都是在上一次调用的基础上减少了1             那么总有一个时刻num的值会满足递归结束条件。     (3)递归案例-阶乘问题         func getJieChengSum(num int) int{             if num<=1{                 return num;             }             tempNum := num;             num--;             return tempNum*getJieChengSum(num);         }         func main() {             sum := getJieChengSum(10);             fmt.Println(sum);         } 3.工程管理     工程管理指的是goland在编译过程中,一个模块化思想的体现。     主要变现为:         1)在一个文件中,可以通过“导入包”的操作后,访问其他文件中的函数。         2)整个工程分为三类文件夹:src(代码源文件)、pkg(编译生成文件)、bin(系统资源文件)     (1)“包”      包,即package。是go语言中为文件分类,而后在编译文件的过程中对文件合并时的一个名词。     包中存放着不同模块,每个模块有着自己独立的功能。     eg:         package user             -userLogin.go             -userRegist.go             ..     此时如果加载了user package这个包,就相当于引入了包中所有模块的功能。     而后就可以通过user包名,来访问包中模块所提供的功能。     eg:         user.Login();//假定Login是userLogin.go文件中声明的方法         user.Regist()//假定Regist是userRegist.go文件中声明的方法     (2)包与文件夹     包并不是文件夹,但是通常包名和包文件所在的文件夹设置为相同名字,以便于理解和查看。     一般上来讲包可以认为是编译完成后在pkg文件夹下的.a文件     (3)导包     导入包的目的其实就相当于JS中的link文件或者script引入文件。其目的都只有一个     那就是在导包后,能够使用包中所提供的不同功能,将工程模块化与组件化。     eg:             import "包路径"         包名.包中提供的接口方法     eg:         src             -test//包名                 -testFile.go//文件名                     package test                     func TTest(){...}//方法名             main.go                 package main                 import "test"//导入时候,使用的是包名                 func main(){                     test.TTest();//调用的时候,也是使用的包名                 }     案例中能够看到在导包结束后,调用包中提供的方法时,使用的是包名而不是文件名!!     (4)注意事项(重点)     由于初学go语言,的确在导入自定义包的这个问题上碰了个大坑。     我使用的是goLang IDE。在导入系统包的时候并不会出现什么问题,主要集中在导入自定义包的时候!     问题:         import 无法检索到自定义包,但是手打却会出现包中方法的系统提示。(虽然运行不了)     缘由:         1)核心到爆炸的问题:             goLang这个坑货IDE在加载包的时候不会主动查找当前路径下的文件,即系统环境变量不能自动配置!             必须采用手动配置的方式,将$GOPATH配置完毕才可以!             eg:                 file -> preferences for New Projects And Settings -> GO -> GOPATH -> + -> 工程目录             注意一点,不要添加src路径进去,而是直接添加目录路径即可!             eg:                 /Users/xxx/Desktop/FuncAndArray             其中FuncAndArray就是我的工程文件夹名称,也就是说直接将工程路径丢在这就可以了!!!!!          2)次要问题              Go语言要求自定义的包中,所提供的模块方法首字母必须大写,否则检索不到!              eg:                  -test                     -testFile.go                         package test                         func tTest(){...}//方法名小写了,导入包后也无法检测到 4.数组     go语言中的数组结构与传统c语言中的结构类似,但是和JS等弱类型语言却截然不同。     eg:         var 数组名 [数组长度]数据类型 = [数组长度]数据类型{初始化的数据内容}     eg:             var arr [10]int = [10]int{10,11,12,13,14,15,16,17,18,19};     对于go语言而言,数组并不是一个可以存放任意数据类型的复杂数据结构。     数组能存放的数据的类型在数组被定义的时候就已经被约定了,     存储约定数据意外的其他数据类型,会导致go语言给出错误提示。     (1)不同的数组初始化方式         var arr [长度]数据类型 = [长度]数据类型 {初始化数据内容};         arr := [长度]数据类型 {初始化数据内容}         arr := [...]数据类型 {初始化数据内容}         arr := []数据类型 {初始化数据内容}          (2)数组不能够通过赋值的方式来进行“硬扩充”         对于弱类型语言中的数组来说,数组的长度是一个动态可变的值。比如在JavaScript中             var arr = [1,2,3];//数组长度最初只有3             arr[100] = 10;//此时数组的长度被扩展到了101         但是对于go语言来说这种方式则一定会报错             arr := [3]int{1,2,3};             arr[100] = 10;//报错,数组下标访问越界!          (3)冒泡排序(我居然在这栽了个跟斗,简直瞎眼,事实证明老 程序员 也会在最基础的地方摔)         arr := [10]int{9,8,7,6,5,4,3,2,1,0};         for i:=0; i<len(arr)-1; i++{             for j:=0; j<len(arr)-1-i; j++{                 if(arr[j]>arr[j+1]){                     temp := arr[j];                     arr[j] = arr[j+1];                     arr[j+1] = temp;                 }             }         }         fmt.Println(arr);          (4)特别注意的是,在go语言中数组作为参数在函数中传入的时候,是值传递!!!         func allAdd(arr [4]int)(resultArr [4]int){             for i,_ := range arr{                 arr[i]++;             }             return arr;         }         func main(){             arr := [4]int{1,2,3,4};             newArr := allAdd(arr);             fmt.Println(arr);//[1,2,3,4] 传入函数后,原数组不会受到任何影响!!             fmt.Println(newArr);//[2,3,4,5]         } 5.随机数     在计算机的编程语言中,随机数的概念其实是不存在的。真正的随机数的名称应当是:概率。     但是我们可以通过计算机时钟来模拟出随机数的样子,也就是伪随机数。     而go语言对于伪随机数的构建不像很多弱类型语言一样封装到脖子,让开发者直接使用     而是需要开发者手动对随机数种子进行时钟混淆,来保证每次获取的样本都不相同。     eg:         rand.Seed(time.Now().UnixNano());         rand.Intn(10);     在go语言中想要使用随机数需要使用到两个系统库,【math/rand】和【time】.     其中time库提供时间函数,来作为随机数种子     而math/rand库则提供随机数函数,从随机数种子混淆后的范围中获取样本。     eg:         rand.Seed(time.Now().UnixNano());         for i:=0;i<100;i++{             ranNum := rand.Intn(100);             fmt.Println(ranNum);         }     注意:rand.Intn()方法获取的随机数是从下界到上界,但是不包括上界的随机数。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Writing Apache Modules with Perl and C

Writing Apache Modules with Perl and C

Lincoln Stein、Doug MacEachern / O'Reilly Media, Inc. / 1999-03 / USD 39.95

Apache is the most popular Web server on the Internet because it is free, reliable, and extensible. The availability of the source code and the modular design of Apache makes it possible to extend Web......一起来看看 《Writing Apache Modules with Perl and C》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

在线进制转换器
在线进制转换器

各进制数互转换器

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码