赞
踩
1.1、函数的定义
Go语言中定义函数使用func关键字,具体格式如下:
有参数和返回值时:
func 函数名(参数 type) (返回值type){
函数体代码return
}有参数无返回值时:
func 函数名(参数 type){
函数体代码}
无参数无返回值时:
func 函数名(){
函数体代码}
- 函数名:由字母、数字、下划线组成。但函数名的第一个字母不能是数字。在同一个包内,函数名也称不能重名(包的概念详见后文)。
- 参数:参数由参数变量和参数变量的类型组成,多个参数之间使用,分隔。
- 返回值:返回值由返回值变量和其变量类型组成,也可以只写返回值的类型,多个返回值必须用()包裹,并用,分隔。
- 函数体:实现指定功能的代码块。
1.2、函数的使用(汇总)
// 定义一个求和函数(有参数),有return返回值时(需要给返回值定义一个类型) func s1(x int, y int) int { return x + y } // 定义一个函数(无参数),有return返回值时(需要给返回值定义一个类型) func s4() string { return "sudada" } // 定义一个求和函数(有参数),没有return返回值时 func s2(x int, y int) { fmt.Println(x + y) } // 定义一个函数(无参数),没有return返回值时 func s3() { fmt.Println("szq") } // return返回值 可以命名(命名后可以直接使用,因为已经做了声明),也可以不命名 // return返回值"szq"在已经声明好的情况下,return后可以什么都不写,默认返回的就是"szq" func s5(x int, y int) (szq int) { szq = x + y return // 这里就可以不写szq,写上也没关系 } // 多个返回值 func s6() (int, string) { return 1, "2" } // 参数类型的简写(2个参数连续且类型一致时,可以这么写) func s7(x, y int) int { return x + y } // 可变长参数(...)必须放在函数参数的最后, y可以不传参,可以传一个参数,也可以传多个参数(拿到的就是一个切片类型的值) func s8(x string, y ...int) { fmt.Println(x) fmt.Println(y) // [1 2 3 4] 拿到的是一个int类型的切片 } // go语音中函数没有默认参数的概念 func main() { fmt.Println(s1(1, 2)) s2(2, 3) s3() fmt.Println(s4()) fmt.Println(s5(2, 2)) fmt.Println(s6()) s8("szq") }1.3、函数传参
1.3.1、形参类型可以简写
函数的参数中如果相邻变量的类型相同,则可以省略类型,例如:
// 参数类型的简写(2个参数连续且类型一致时,可以这么写) func s7(x, y int) int { return x + y }上面的代码中,s7函数有两个参数,这两个参数的类型均为int,因此可以省略x的类型,因为y后面有类型说明,x参数也是该类型。
1.3.2、可变长参数
可变参数是指函数的参数数量不固定。Go语言中的可变参数通过在参数名后加...来标识。
注意:可变参数通常要作为函数的最后一个参数。
// 可变长参数(...)必须放在函数参数的最后, y可以不传参,可以传一个参数,也可以传多个参数(拿到的就是一个切片类型的值) func s8(x string, y ...int) { fmt.Println(x) fmt.Println(y) // [1 2 3 4] 拿到的是一个int类型的切片 }可变长参数使用:
func intSum2(x ...int) int { fmt.Println(x) // x是一个切片 sum := 0 // for range循环时,key是索引,value是值 for _, v := range x { sum = sum + v } return sum } func main() { ret1 := intSum2() ret2 := intSum2(10) ret3 := intSum2(10, 20) ret4 := intSum2(10, 20, 30) fmt.Println(ret1, ret2, ret3, ret4) //0 10 30 60 }固定参数搭配可变参数使用时,可变参数要放在固定参数的后面,示例代码如下:
func intSum3(x int, y ...int) int { fmt.Println(x, y) sum := x for _, v := range y { sum = sum + v } return sum } func main() { ret5 := intSum3(100) ret6 := intSum3(100, 10) ret7 := intSum3(100, 10, 20) ret8 := intSum3(100, 10, 20, 30) fmt.Println(ret5, ret6, ret7, ret8) //100 110 130 160 }本质上,函数的可变参数是通过切片来实现的。
1.4、函数 返回值
Go语言中通过return关键字向外输出返回值。
1.4.1、多返回值
Go语言中函数支持多返回值,函数如果有多个返回值时必须用()将所有返回值包裹起来。
func calc(x, y int) (int, int) { sum := x + y sub := x - y return sum, sub } func main() { a, b := calc(1, 2) fmt.Println(a) fmt.Println(b) }1.4.1、多返回值命名
函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return关键字返回。
// return返回值 可以命名(命名后可以直接使用,因为已经做了声明),也可以不命名 // return返回值"szq"在已经声明好的情况下,return后可以什么都不写,默认返回的就是"szq" func s5(x int, y int) (szq int) { szq = x + y return // 这里就可以不写szq,写上也没关系 } // 例子2 func calc(x, y int) (sum, sub int) { sum = x + y sub = x - y return } func main() { a, b := calc(1, 2) fmt.Println(a) fmt.Println(b) }1.5、函数的递归调用(在函数体内又调用了函数本身)
函数递归需要遵守的重要原则:
1.执行一个函数时,就创建一个新的受保护的独立空间。
2.函数的局部变量是独立的,不会相互影响。
3.递归必须向退出递归的条件逼近(例子里面的"x--"),否则就是死循环。
4.当一个函数执行完毕,或者遇到return,就会返回,遵循谁调用,就将返回结果给谁。同时函数执行完毕或被返回时,该函数本身也会被回收。
package main import ( "fmt" ) func test(x int) { if x > 2 { // 递归必须向退出递归的条件逼近 x-- test(x) } fmt.Println(x) } func test1(x int) { if x > 2 { // 递归必须向退出递归的条件逼近 x-- test1(x) } else { fmt.Println(x) } } func main() { test(4) // 返回值:2,2,3 test1(4) // 返回值:2 }1.6、init函数
init函数会在main函数执行之前调用,通常在init函数中完成初始化的工作
package main import "fmt" func init() { fmt.Println("init") } func main() { fmt.Println("main") } // 返回值: init main细节:
1、一个文件同时包含全局变量定义,init函数和main函数,则执行的顺序是:全局变量定义 -> init函数 -> main函数
package main import "fmt" var age = test() func test() int { fmt.Println("test") return 90 } func init() { fmt.Println("init") } func main() { fmt.Println("main") } // 返回值:test init main
包的基本语法:package "包名"
引入包:import "包的路径"
使用包内的函数:"包名".xxx
2.1、包的简单使用例子
// 外部的包(utils.go) package utils // 这个函数是给外部使用(该函数可以导出),所以函数首字母大写 func Calc(x, y int) (sum , sub int) { sum = x + y sub = x - y return } // 引用包(main.go) package main import ( "fmt" "Study/go006/utils" // abc "Study/go006/utils" 还可以写成别名的方式,使用的使用就是abc.xxx ) func main() { a, b := utils.Calc(20, 10) fmt.Println(a, b) // 返回值:30,10 }2.2、包的注意事项
1.文件的包名(package utils)通常和文件(utils.go)所在的文件夹名(utils)一致,一般为小写字母。
2.import "PATH/包名(文件夹名)"
2.1.在import包时,路径从$GOPATH的src目录下开始(不包含src),编译器会自动从src目录下开始引用。
3.使用包的数据utils.xxx时,这里的utils就是"包名(package utils)",如果包名改为"(package abc)",那么使用时就要写成abc.xxx
4.包内(可以导出的)函数、变量,首字母必须大写。
5.如果给包(utils)起了别名为(abc),那么在使用包时,使用别名即可abc.xxx
6.同一个包下,不能有重复函数名,全局变量名
7.如果要编译一个可执行的文件,就需要将这个包声明为main (main包只能有一个),即package main,如果是一个库文件,则包名可以自定义。(编译时需要编译main包所在的文件夹)
3.1、全局变量
全局变量是定义在函数外部的变量,它在程序整个运行周期内都有效。 在函数中可以访问到全局变量。
函数中查找变量的顺序:
1.先在函数的内部查找
2.找不到就往函数的外面查找,一直找到全局,如果找不到就报错。
var szq = 123 func s0() { fmt.Println(szq) } func main() { s0() // 123 }3.2、局部变量
1.局部变量又分为两种: 函数内定义的变量无法在该函数外使用
func testLocalVar() { //定义一个函数局部变量x,仅在该函数内生效 var x int64 = 100 fmt.Printf("x=%d\n", x) } func main() { testLocalVar() fmt.Println(x) // 此时无法使用变量x }2.如果局部变量和全局变量重名,优先访问局部变量。
//定义全局变量num var num int64 = 10 func testNum() { num := 100 fmt.Printf("num=%d\n", num) // 函数中优先使用局部变量 } func main() { testNum() // num=100 }3.3、语句块定义的变量
1.通常我们会在if条件判断、for循环、switch语句上使用这种定义变量的方式。
func testLocalVar2(x, y int) { fmt.Println(x, y) //函数的参数也是只在本函数中生效 if x > 0 { z := 100 //变量z只在if语句块生效 fmt.Println(z) } fmt.Println(z) //此处无法使用变量z } func main() { testLocalVar2(1,2) }2.还有for循环语句中定义的变量,也是只在for语句块中生效:
func testLocalVar3() { for i := 0; i < 10; i++ { fmt.Println(i) //变量i只在当前for语句块中生效 } fmt.Println(i) //此处无法使用变量i } func main() { testLocalVar3() }
4.1、定义函数类型
4.1.1.什么是函数类型,举个例子:
// 函数作为参数赋值给变量时,有哪些类型 func s1(){ fmt.Println("szq") } func s2() int{ return 18 } func s3(x int) int{ return x+1 } func main() { a := s1 // 打印变量a的类型 fmt.Printf("%T\n",a) //func():这是一个普通的函数类型 a() // 此时a就等于函数s1,加()即可执行该函数,返回值"szq" b := s2 // 打印变量b的类型 fmt.Printf("%T\n",b) //func() int :这是一个函数类型(包括函数的返回值类型) fmt.Println(b()) // 此时b就等于函数s2,加()即可执行该函数,返回值18 c := s3 // 打印变量c的类型 fmt.Printf("%T\n",c) //func(int) int :这是一个函数类型(包括函数的参数类型和函数的返回值类型) fmt.Println(c(1)) // 此时c就等于函数s3,加()即可执行该函数,返回值2 }4.1.2.函数作为一个参数
// 一、函数作为参数时,无形参 // 定义函数s1 func s1() int { return 18 } // s1函数作为参数传递给s2函数 // x func() int 说明: // "x"(形参的名称) // "func() int"形参x的类型是一个"函数类型",该函数有一个返回值,返回值的类型是int func s2(x func() int){ res := x() fmt.Println(res) } func main() { re1 := s1 // 将函数赋值给变量re1 fmt.Printf("%T\n",re1) // func() int s2(s1) // 函数s1作为参数传递给函数s2(s1函数的类型必须满足s2的接收参数类型,即:func() int) s2(re1) // 变量re1作为参数传递给函数s2(变量re1的类型必须满足s2的接收参数类型,即:func() int) } // 二、函数作为参数时,有形参 func s3(x int) int{ return x+1 } // funvar func(int) int 说明: // "funvar"(形参的名称) // "func(int) int"形参funvar的类型是一个"函数类型",该函数会接收一个参数,参数类型是int,并且有一个返回值,返回值的类型是int func szq(funvar func(int) int, num int) int { res := funvar(20) // 这里funvar(20)就等于s3(20),拿到的是函数s3的执行结果 return res + num } func main() { fmt.Println(szq(s3,10)) // 返回值:31 }4.1.3.函数作为一个返回值
// 定义函数s1 func s1() int { return 18 } func ff(a int,b int)int{ return a+b } // 函数作为一个返回值返回 // x func() int :形参x的类型是一个"函数类型",该函数有一个返回值,返回值的类型是int // y func(int,int)int :"函数s3的返回值类型是一个"函数类型",该函数会接收2个参数,参数类型是int,并且有一个返回值,返回值的类型是int func s3(x func() int)(y func(int,int) int){ fmt.Println(x()) res := func(a int,b int)int{ return a+b } //res := ff // 这里也可以换一种写法,ff函数的格式需要满足y即可 return res } func main() { szq := s3(s1) // 把函数s1做为参数传入到函数s3中,执行函数s3的代码后会打印18,并且拿到一个返回值res,此时的res是一个函数类型。 fmt.Println(szq(1,2)) // 拿到的返回值res类型为"函数类型:func(int,int)int",那么就可以正常的传值,查看执行结果 } //返回结果: //18 //34.2、函数类型的变量 (变量的类型为函数类型,然后为该变量赋值)
了解以上函数类型之后,我们可以使用type关键字来定义一个函数类型的变量,具体格式如下:
type myFun func(int, int) int
上面语句定义了一个变量myFun,是一个函数类型,这种函数接收两个int类型的参数并且返回一个int类型的返回值。
package main import "fmt" // 定义一个变量"myFunc",类型为函数类型(函数需要接收2个int类型的参数,并有一个返回值也是int类型) type myFunc func(int, int) int // 定义一个全局变量c,c的类型myFunc var c myFunc // 定义一个普通函数,类型为:add(x, y int) int func add(x, y int) int { return x + y } // 形参 n func(int, int) int 可以写成 n myFunc (变量myFunc的类型就是函数类型) func szq(a,b int, n myFunc) int { res := n(a,b) return res } func main() { c = add // 给变量c做赋值操作(变量c = add函数) fmt.Println(add(1,2)) // 返回值为:3 fmt.Printf("%T\n",c) // main.myFunc fmt.Println(c(1,2)) // 像调用add一样调用c,返回值为:3 fmt.Println(szq(1,2, add)) // 返回值为:3 }
5.1、Go语言中的
defer
语句会将其后面跟随的语句进行延迟处理。在
defer
归属的函数即将返回时(简单理解为函数内的逻辑执行完毕后,在执行defer语句),将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句,最先被执行(先入后出)简单例子:
func main() { fmt.Println("start") defer fmt.Println(1) defer fmt.Println(2) defer fmt.Println(3) fmt.Println("end") } //输出结果: //start //end //3 //2 //1由于
defer
语句延迟调用的特性,所以defer
语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。5.2、defer的执行时机(先给返回值赋值,然后执行defer,最后执行return)
在Go语言的函数中
return
语句在底层并不是原子操作,它分为给返回值赋值和RET(return)指令两步。而defer
语句执行的时机就在返回值赋值操作后,RET(return)指令执行前。具体如下图所示:简单例子:
package main import "fmt" func sum(a,b int) int { defer fmt.Println("3") defer fmt.Println("2") defer fmt.Println("1") res := a+b fmt.Println("sum", res) return res } func main() { fmt.Println("main") res := sum(2,3) fmt.Println("mian-res", res) } // 返回值 // main // sum 5 // 1 // 2 // 3 // mian-res 55.3、defer经典案例
// 第一步:返回值赋值 //defer //第二步:真的的return,返回一个值 func f1() int { x := 5 defer func() { x++ // 修改的是x,不是返回值 }() return x } func f2() (x int) { defer func() { x++ }() return 5 // 返回值为x } func f3() (y int) { x := 5 defer func() { x++ // 修改的是x }() return x // 返回值为y,y的值=x=5 } func f4() (x int) { defer func(x int) { x++ // 改变的是函数中的副本 }(x) return 5 // 返回值=x=5 } func main() { fmt.Println(f1()) //5 fmt.Println(f2()) //6 fmt.Println(f3()) //5 fmt.Println(f4()) //5 }5.4、defer面试题
func calc(index string, a, b int) int { ret := a + b fmt.Println(index, a, b, ret) return ret } func main() { // var x int = 1 x := 1 // var y int = 2 y := 2 // 函数内套用函数调用时,代码走到这一层就会先执行函数内的函数,会把对应变量的值传过去。 即:defer calc("AA", 1, calc("A", 1, 2)) == defer calc("AA", 1, 3),详见下面的分析结果: defer calc("AA", x, calc("A", x, y)) // 这里的x因为在前面已经做了定义,所以可以直接用"="号赋值 x = 10 // 函数内套用函数调用时,代码走到这一层就会先执行函数内的函数,会把对应变量的值传过去即:defer calc("BB", 10, calc("B", 10, 2)) == defer calc("BB", 10, 12),详见下面的分析结果: defer calc("BB", x, calc("B", x, y)) // 这里的y因为在前面已经做了定义,所以可以直接用"="号赋值 y = 20 } // 分析以上代码的执行过程: // 1)x := 1 // 2)y := 2 // 3)defer calc("AA", x, calc("A", x, y)) == defer calc("AA", 1, calc("A", 1, 2)) == defer calc("AA", 1, 3) // 4)x = 10 // 5)defer calc("BB", x, calc("B", x, y)) == defer calc("BB", 10, calc("B", 10, 2)) == defer calc("BB", 10, 12) // 6)y = 20 // 7)defer calc("BB", 10, 12) == BB 10 12 22 // 8)defer calc("AA", 1, 3) == AA 1 3 4 //输出结果: //A 1 2 3 先执行函数内的函数 //B 10 2 12 先执行函数内的函数 //BB 10 12 22 在按照defer的逻辑,最后定义的最先执行 //AA 1 3 4 按照defer的逻辑,最先定义的最后执行
6.1、匿名函数 (匿名函数多用于实现回调函数和闭包,匿名函数一般都用在函数内部)
函数当然还可以作为返回值,但是在Go语言中函数内部不能再像之前那样定义函数了,只能定义匿名函数。匿名函数就是没有函数名的函数,匿名函数的定义格式如下:
func (参数) (返回值){
函数体
}1.把匿名函数赋值给一个变量:
// 匿名函数使用1:将匿名函数赋值给一个"全局"变量,该匿名函数可以任意地方使用 var f1 = func(x,y int){ fmt.Println(x+y) } func main() { f1(1,2) // 调用变量f1就是调用匿名函数,返回值为:3 // 匿名函数使用2:在函数内部将匿名函数赋值给一个变量,该匿名函数只能在函数内部使用 f2 := func(x,y int){ fmt.Println(x+y) } f2(10,20) // 调用匿名函数,返回值为:3 // 如果只是调用一次的函数,可以简写成"立即执行函数" func(x,y int){ fmt.Println(x+y) }(2,3) // 调用"立即执行函数",返回值为:5 }2.匿名函数作为立即执行函数(只是一次调用的函数):
func main() { // 如果只是调用一次的函数,可以简写成"立即执行函数" func(x,y int){ fmt.Println(x+y) }(2,3) // 调用"立即执行函数",返回值为:5 }6.2、闭包 (一个函数既"引用了函数内的变量",又"引用了函数外的变量")
闭包的底层原理:
1.函数可以作为返回值,
2.函数内部查找顺序:先在函数内找,然后在到函数外部找。闭包指的是一个函数和与其相关的引用环境组合而成的实体。简单来说,
闭包=函数+引用环境
。 首先我们来看一个例子:
// 例子1: // 闭包的实际应用,要求:s1(s2) 把s2作为参数传入到s1 func s1(f func()) { fmt.Println("s1") f() } func s2(x, y int) { fmt.Println("s2") fmt.Println(x + y) } //s3函数要接收s2函数的传参,并且返回值的类型要符合s1函数参数类型 //f func(int, int), x, y int 这些都是给s2函数使用的 //func() 这个是给s1函数使用的 func s3(f func(int, int), x, y int) func() { res := func() { f(x, y) } return res // 这里的返回值res是一个func()类型,符合s1函数的接收类型 } func main() { ret := s3(s2, 100, 300) // 这里ret也就等于s3函数内的res s1(ret) // s1函数传入ret,本质上执行的是s2函数的代码。 } //输出结果 //s1 //s2 //400 // 例子2: import "fmt" // 函数的返回值是一个匿名函数,但这个匿名函数引用到函数外的变量n,因此这个匿名函数就和变量n形成一个整体,构成闭包。 // 当反复调用f函数时,因为n只初始化一次,因此每调用一次就进行累计。 func addUpper() func(int) int { var n int = 10 return func(x int) int { n = n +x return n } } func main() { f1 := addUpper() fmt.Println(f1(1)) // 返回值:11 fmt.Println(f1(2)) // 返回值:13 fmt.Println(f1(3)) // 返回值:16 }例子2:在函数内修改函数的参数值
func calc(base int) (func(int) int, func(int) int) { add := func(i int) int { base += i return base } sub := func(i int) int { base -= i return base } return add, sub } func main() { f1, f2 := calc(10) fmt.Println(f1(1), f2(2)) //11 9,这里每次改的都是calc函数内的base,也就是说随着每次的改修,base的值会发生改变。 fmt.Println(f1(3), f2(4)) //12 8 fmt.Println(f1(5), f2(6)) //13 7 }
7.1、内置函数介绍
内置函数 介绍 close 主要用来关闭channel len 用来求长度,比如string、array、slice、map、channel new 用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针 make 用来分配内存,主要用来分配引用类型,比如channel、map、slice append 用来追加元素到数组、slice中 panic和recover 用来做错误处理 7.2、panic 主动抛出异常
func funcA() { fmt.Println("func A") } func funcB() { panic("出现了严重的错误!") // 主动报错 } func funcC() { fmt.Println("func C") } func main() { funcA() funcB() funcC() } // 输出结果: // func A // 报错之前执行的代码 // panic: 出现了严重的错误! // 报错的输出 // goroutine 1 [running]: // main.funcB(...) // 报错的代码位置点 // /Users/suzhaoqiang/Desktop/Go/Goland_Document/学习过程/2021-8-16/05.go:10 // main.main() // 报错代码的执行点 // /Users/suzhaoqiang/Desktop/Go/Goland_Document/学习过程/2021-8-16/05.go:18 +0x967.3、panic + recover + defer 接收错误信息后,抛出异常提示,同时代码继续执行
Go中可以抛出一个panic的异常,然后再defer中通过recover捕获这个异常,然后正常执行代码。
注意:
recover()必须搭配defer使用。
defer一定要在可能引发panic的语句之前定义。例子1:使用panic抛出异常,然后使用recover + defer捕捉异常
func funcA() { fmt.Println("func A") } func funcB() { defer func() { err := recover() // recover()拿到的就是panic的输出。使用recover()后程序不会崩溃退出,继续往下执行。 fmt.Println(err) }() panic("出现了严重的错误!") // defer要在panic之前定义,否则panic程序崩溃,没法执行defer语句了。 } func funcC() { fmt.Println("func C") } func main() { funcA() funcB() funcC() } //输出结果: //func A //出现了严重的错误! //func C例子2:使用recover + defer 捕捉异常
import "fmt" // 使用defer + recover来捕获和处理异常 func test() { defer func() { err := recover() // "recover()"是一个内置函数,可以捕捉到异常 if err != nil { // 如果错误不为空,说明捕捉到了异常 fmt.Println(err) // 输出异常信息 } }() a := 10 b := 0 res := a / b fmt.Println(res) } func main() { test() // 抛出异常信息:runtime error: integer divide by zero fmt.Println("main代码逻辑") }例子3:使用自定义错误:errors.New("读取文件失败")
import ( "errors" "fmt" ) func test(name string) (err error) { if name == "config.ini" { return nil } else { // 返回一个自定义错误 return errors.New("读取文件失败") } } func test02() { err := test("config.123") if err != nil { // 读取文件发生错误时,输出自定义错误,并终止程序 panic(any(err)) // Golang 1.18 版本开始引入any类型可以替代空接口 interface{} ,直接写成panic(err)会有错误提示,但是执行不会报错 } fmt.Println("test02...") } func main() { test02() fmt.Println("main...") } // 返回值:panic: 读取文件失败7.4、内置函数(rune,strconv,byte)例子
package main import ( "fmt" "strconv" ) func main() { str2 := "hello上海" // 字符串便利时,处理有中文的场景,使用:"[]rune(xxx)" str3 := []rune(str2) for n := 0; n < len(str3); n++ { fmt.Printf("%c\n",str3[n]) // 返回值:"hello上海" } // 字符串转为整数 num, err := strconv.Atoi("123") // err == nil时,说明无报错 if err != nil { fmt.Println("error: ",err) } else { fmt.Println("value: ",num) } // 整数转化为字符串 str := strconv.Itoa(12345) fmt.Println("str value: ",str) // 返回值:str value: 12345 // 字符串转[]byte var bytes = []byte("hello go") fmt.Printf("%v\n",bytes) // 返回值:[104 101 108 108 111 32 103 111] // byte转字符串 str1 := string([]byte{97,98,99}) fmt.Printf("%v\n",str1) // 返回值:abc }7.5、内置函数 new(用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针)
import "fmt" func main() { var num int = 100 fmt.Printf("%T %v %v\n",num,num,&num) // 返回值:int 100 0xc00000a0e8 num2 := new(int) *num2 = 100 fmt.Printf("%T %v %v %v\n",num2,num2,&num2,*num2) // 返回值:*int 0xc00000a108 0xc00006a028 100 }7.6、内置函数 make(用来分配内存,主要用来分配引用类型,比如channel、map、slice)
八、常用模块
8.1、strings模块的常用方法
import ( "fmt" "strings" ) func main() { // 查找指定字符串 // 判断字符串"food"是否存在于"seafood"中,存在返回true不存在返回false b := strings.Contains("seafood","food") fmt.Printf("%v\n",b) // 返回值:true // 判断字符串"asd"是否存在于"seafood"中,存在返回true不存在返回false c := strings.Contains("seafood","asd") fmt.Printf("%v\n",c) // 返回值:false // 统计字符串的数量 // 字符串"e"在"cehese"出现的次数 num1 := strings.Count("cehese","e") fmt.Printf("%v\n",num1) // 返回值:false // 字符串替换,1指的是替换1次,为-1表示替换全部 // 把"go"替换为"go语言",针对"go go hello"做替换 str4 := strings.Replace("go go hello","go","go语言",-1) fmt.Println(str4) // 返回值:"go语言 go语言 hello" // 字符串指定分隔符,得到一个数组 fmt.Println(strings.Split("hello,world",",")) // 返回值:[hello world] // 字母大小写转换 fmt.Println(strings.ToLower("Go")) // 返回值:gp fmt.Println(strings.ToUpper("Go")) // 返回值:GO // 字符串去掉两边的空格 fmt.Println(strings.TrimSpace(" is shanghai ")) // 返回值:"is shanghai" // 字符串去掉左右两边指定的字符串 fmt.Println(strings.Trim("! hello !","!")) // 返回值: " hello " // 去掉字符串左边指定的字符 fmt.Println(strings.TrimLeft("to shanghai","to")) // 返回值: " shanghai" // 去掉字符串右边指定的字符 fmt.Println(strings.TrimRight("to shanghai gogo","gogo")) // 返回值:"to shanghai" // 字符串是否以指定的字符串开头 fmt.Println(strings.HasPrefix("www.baidu.com","www")) // 返回值:true // 字符串是否以指定的字符串结尾 fmt.Println(strings.HasSuffix("www.baidu.com","com")) // 返回值:true }8.2、time模块
8.2.1、常用方法
import ( "fmt" "time" ) func main() { now := time.Now() fmt.Printf("%v \n",now) // 返回值:2023-10-22 19:49:50.0430013 +0800 CST m=+0.001257301 fmt.Println(now.Year()) // 返回值:年 fmt.Println(now.Month()) // 返回值:月(英文月份) fmt.Println(int(now.Month())) // 返回值:月(数字) fmt.Println(now.Day()) // 返回值:日 fmt.Println(now.Hour()) // 返回值:时 fmt.Println(now.Minute()) // 返回值:分 fmt.Println(now.Second()) // 返回值:秒 // 格式化时间,方式1: dateStr := fmt.Sprintf("当前时间: %d/%d/%d %d:%d:%d",now.Year(), now.Month(),now.Day(),now.Hour(),now.Minute(),now.Second(), ) fmt.Printf("%v\n",dateStr) // 返回值:当前时间: 2023/10/22 20:2:38 // 格式化时间,方式2: fmt.Println(now.Format("2006-01-02 15:04:05")) // 返回值:当前时间的"年-月-日 时:分:秒" fmt.Println(now.Format("2006-01-02")) // 返回值:当前时间的"年-月-日" fmt.Println(now.Format("15:04:05")) // 返回值:当前时间的"时:分:秒" fmt.Println(now.Format("2006")) // 返回值:当前时间的"年" fmt.Println(now.Format("01")) // 返回值:当前时间的"月" fmt.Println(now.Format("02")) // 返回值:当前时间的"日" fmt.Println(now.Format("15")) // 返回值:当前时间的"时" fmt.Println(now.Format("04")) // 返回值:当前时间的"分" fmt.Println(now.Format("05")) // 返回值:当前时间的"秒" }8.2.2、时间常量
time.Microsecond:1微妙
time.Millisecond:1毫秒
time.Second:1秒
time.Minute:1分钟
time.Hour:1小时
import ( "fmt" "time" ) func main() { // 时间常量 // time.Microsecond:1微妙 // time.Millisecond:1毫秒 // time.Second:1秒 // time.Minute:1分钟 // time.Hour:1小时 // 等待1秒 time.Sleep(time.Second) // 等待10秒 time.Sleep(10 * time.Second) // 获取时间戳 now := time.Now() fmt.Println(now.Unix()) // 返回值:1697989319 }8.2.3、获取函数的执行时间小例子
import ( "fmt" "strconv" "time" ) func test() { str := "" for i:=0;i<=100000;i++{ str += "hello" + strconv.Itoa(i) } } func main() { now_time := time.Now().Unix() test() end_time := time.Now().Unix() res := end_time-now_time fmt.Println(res) // 返回值:5 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。