Go语言函数、包
Go语言函数、包
函数使用:
①函数的形参列表可以是多个,返回值列表也可以是多个。
②形参列表和返回值列表的数据类型可以是值类型和引用类型。
③函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本包文件和其它包文件使用,类似 public,首字母小写,只能被本包文件使用,其它包文件不能使用,类似 private。
④函数中的变量是局部的,函数外不生效。
⑤基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。
⑥如果希望函数内的变量能修改函数外的变量(指的是默认以值传递的方式的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量。Test(&num)
⑦Go语言不支持函数重载
⑧在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用。

⑨函数可作为形参,并且调用。

⑩Go支持自定义数据类型:基本语法:type自定义数据类型名数据类型
案例:type mySum func (int, int) int
这时mxSum就等价一个函数类型func(int, int)int
①支持对函数返回值命名

②使用_标识符,忽略返回值。
③支持可变参数。
args是slice切片,通过args[index]可以访问到各个值。
如果一个函数的形参列表中有可变参数,则可变参数需要放在形参列表最后。
Init函数
每一个源文件都可以包含一个init函数,其会在main函数执行前,被Go运行框架调用。
①如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程:
全局变量定义 → init函数 →main函数
②主要完成初始化操作。
③案例如果main.go和utils.go都含有变量定义,init函数时,执行的流程:

匿名函数
使用方法:
①在定义匿名函数时就直接调用【只能调用一次】

②将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数

全局匿名函数:将匿名函数赋给一个全局变量

闭包:一个函数和与其相关的引用环境组合的一个整体(实体)。
请编写一个程序,具体要求如下
①编写一个函数makeSuffix(suffix string)可接收一个文件后缀名(如.jpg),并返回一个闭包。
②调用闭包,可以传入一个文件名,如果该文件名无指定的后缀(如.ipg) ,则返回文件名.jpg;若有.jpg后缀,则返回原文件名。
③要求使用闭包的方式完成
④strings.HasSuffix,该函数可以判断某个字符串是否有指定的后缀。

返回的匿名函数和makesSuffix (suffix string)的suffix变量组合成一个闭包,因为返回的函数引用到suffix这个变量。
传统方法需要每次都传入后缀名,而闭包因为可以保留上次引用的某个值,所以我们传入一次就可以反复使用。
函数的defer(延时机制)
在函数中,程序员经常需要创建资源(如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,Go的设计者提供 defer。

①当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中,然后继续执行函数下一个语句。
②当函数执行完毕后,再从defer栈中,依次从栈顶取出语句执行。
③在defer将语句放入到栈时,也会将相关的值拷贝同时入栈。

defer最主要的价值是在,当函数执行完毕后,可以及时的释放函数创建的资源。
①在golang编程中的通常做法是,创建资源后,比如(打开了文件,获取了数据库的链接,或者是锁资源),可以执行defer file.Close() ;defer connect.Close()
②在 defer后,可以继续使用创建资源。
③当函数完毕后,系统会依次从defer栈中,取出语句,关闭资源。
④这种机制,非常简洁,程序员不用再为在什么时机关闭资源而烦心。
函数传递:
不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝。
值类型:基本数据类型int 系列, float系列,bool,string、数组和结构体struct
引用类型:指针、slice 切片、map、管道chan、interface等都是引用类型
变量作用域:
①函数内部声明/定义的变量叫局部变量,作用域仅限于函数内部
②函数外部声明/定义的变量叫全局变量,作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效。
③如果变量是在一个代码块,这个变量的的作用域就在该代码块。

字符串常用的系统函数:
①统计字符串的长度,按字节len(str)
②字符串遍历,同时处理有中文的问题r :=[]rune(str)
③字符串转整数: n, err := strconv.Atoi("12")
④整数转字符串:str =strconx.Itoa(12345)
⑤字符串转[]byte: var bytes =[]byte("hello go")
⑥[]byte转字符串: str = string([]byte {97,98,99})
⑦10进制转2,8,16进制: str = strconv.FormatInt(123,2)//2→8,16
⑧查找子串是否在指定的字符串中: strings.Contains("seafood", "foo")//true
⑨统计一个字符串有几个指定的子串 :strings.Count("ceheese", "e")//4
⑩不区分大小写的字符串比较:fmt.Println(strings.EqualFold("abc."Abc"))// true
(==是区分字母大小写的)
①返回子串在字符串第一次出现的index值,如果没有返回-1 :
strings.Index("NLT_abc", "abc")// 4
②返回子串在字符串最后一次出现的index,如没有返回-1 :
strings.LastIndex("go golang","go")//3
③将指定的子串替换成另外一个子串: strings.Replace("go go hello" , "go" , "go语言", n)n可以指定你希望替换几个,如果n=-1表示全部替换
④按照指定的某个字符,为分割标识,将一个字符串拆分成字符串 strings.Split("hello,wrold.ok", ",")
⑤将字符串的字母进行大小写的转换: strings.ToLower("Go")ll go strings.ToUpper("Go")// GO
⑥将字符串左右两边的空格去掉:strings.TrimSpace(" tn a lone gopher ntrm ")
⑦将字符串左右两边指定的字符去掉:strings.Trim("! hello! ", " !")
⑧将字符串左边指定的字符去掉:strings.TrimLeft("! hello! ", " !")
⑨将字符串右边指定的字符去掉: strings.TrimRight("! hello! "," !")
⑩判断字符串是否以指定的字符串开头: strings.HasPrefix("ftp://192.168.10.1" , "ftp")//true
①判断字符串是否以指定的字符串结束: strings.HasSuffix("NLT_abc.jipg" , "abc")//false
时间和日期:
①导入time包
②获取信息:now := time.Now( ) now.Minute() now.Year()
③格式化日期:
A.Printf或SPrintf

B.time.Format( )

④时间的常量:得到100毫秒:100*time.Millisecond

⑤结合Sleep使用时间常量:time.sleep(time.Millisecond* 100)
⑥time的Unix和UnixNano的方法
func (t Time) Unix( ) int64:
从时间点January 1,1970 UTC到时间点t所经过的时间(单位秒)
func (t Time) UnixNano( ) int64:
从时间点January 1, 1970 UTC到时间点t所经过的时间(单位纳秒)。如果纳秒为单位的unix时间超出了int64能表示的范围,结果是未定义的。注意这就意味着Time零值调用UnixNano方法的话,结果是未定义的。
内置函数
这些函数可直接使用,称为Go的内置函文档:https://studygolang.com/pkgdoc -> builtin。
①len:求长度,比如string、array、slice、map、channel。
②new:分配内存,主要分配值类型,比如int、float32,struct ...返回的是指针。
③make:分配内存,主要分配引用类型,比如channel、map、slice。
错误处理
①Go语言不支持try…catch…finally这种处理。
②Go中引入的处理方式为:defer,panic,recover。
Go中可以抛出一个panic的异常 → 在defer中通过recover捕获这个异常 → 正常处理。

③进行错误处理后,程序不会轻易挂掉,如果加入预警代码,就可以让程序更加的健壮。

自定义错误:使用errors.New和panic内置函数。
① errors.New("错误说明"),会返回一个error类型的值,表示一个错误
② panic内置函数,接收一个interface{}类型的值(也就是任何值了)作为参数。可以接收 error类型的变量,输出错误信息,并退出程序。
