3 程序流程控制-函数、包【Go语言教程】
一、 程序流程控制
- 顺序控制
- 分支控制
- switch分支
- for循环
Go 语言没有 while 和 do…while 语法,这一点需要同学们注意一下,如果我们需要使用类似其它语言(比如 java / c 的 while 和 do…while ),可以通过 for 循环来实现其使用效果。
1.1 if-else多分支
题目:
①多分支的快速入门案例
岳小鹏参加 Golang 考试,他和父亲岳不群达成承诺: 如果:
成绩为 100 分时,奖励一辆 BMW;
成绩为(80,99]时,奖励一台 iphone7plus; 当成绩为[60,80]时,奖励一个 iPad;
其它时,什么奖励也没有。
请从键盘输入岳小鹏的期末成绩,并加以判断代码如下:
package main
import (
"fmt"
_ "unsafe"
_ "strconv"
_ "go_code/project01/main/model"
)
func main(){
var score float64
fmt.Println("请输入岳小鹏的成绩:")
fmt.Scanln(&score)
if score == 100 {
fmt.Println("奖励一辆BMW")
} else if score >= 80 && score <= 90 {
fmt.Println("奖励里一台iphone7Plus")
} else if score >= 60 && score < 80 {
fmt.Println("奖励一个iPad")
} else{
fmt.Println("嘛也没有...")
}
}
1.2 switch多分支
go语言中,case的匹配项中不需要添加break
- golang 的 case 后的表达式可以有多个,使用 逗号 间隔.
- golang 中的 case 语句块不需要写 break , 因为默认会有,即在默认情况下,当程序执行完 case 语句块后,就直接退出该 switch 控制结构。
- switch 穿透-fallthrough ,如果在 case 语句块后增加 fallthrough ,则会继续执行下一个 case,也叫 switch 穿透
import (
"fmt"
)
func main(){
var num int
fmt.Println("请输入一个数字")
fmt.Scanf("%d", &num)//%d接收数字
switch num {
case 15,14,12:
fmt.Println("ok1")
fallthrough //默认只能穿透一层
case 10,9:
fmt.Println("ok2")
case 5,4:
fmt.Println("ok3")
case 0:
fmt.Println("ok4")
default :
fmt.Println("default....")
}
}
//写一个简单的函数
func getNum(n int) int {
fmt.Println("this is num", n)
return 13
}
使用场景区分:
- 判断的具体数值不多,而且符合整数、浮点数、字符、字符串这几种类型。建议使用 swtich语句,简洁高效。
- 其他情况:对区间判断和结果为bool类型的判断使用if
1.3 for、break、continue
1.3.1 for循环
例:遍历含有中文的字符串
注意:
go语言中没有while、do-while的写法,但是我们可以通过for循环来实现类似效果- 编程时候的技巧:
(1) 先易后难, 即将一个复杂的问题分解成简单的问题。
(2) 先死后活
方法一:采用for循环
package main
import (
"fmt"
)
func main(){
str := "hello, 中国"
//go语言采用utf8编码,字母和数字均占一个字节,中文则占三个字节
//因此,需要将含有中文的str转换为[]rune切片
arr := []rune(str)
for i := 0; i < len(arr); i++ {
fmt.Printf("value=%c \n", arr[i])
}
}
方法二:采用for-range
func main(){
str := "hello, 中国"
for i, val := range str {
fmt.Printf("index=%d, val=%c \n", i, val)
}
}
1.3.2 break跳出
break 语句用于终止某个语句块的执行,用于中断当前 for 循环或跳出 switch 语句。
有多层循环时候,break可以通过标签指明跳出哪一个循环
【默认跳最近】
案例①:
通过break跳出循环
package main
import (
"fmt"
"time"
"math/rand"
_ "go_code/project01/main/model"
)
func main(){
//生成随机数,需要给rand设置一个种子
//time.Now().Unix():返回一个从1970:01:01的0时0分0秒到现在的秒数
//rand.Seed(time.Now().Unix())
//随机生成一个1-100的整数,当生成了50的时候,跳出
var count int = 0
//用for实现类似于while的方式
for {
rand.Seed(time.Now().UnixNano())
n := rand.Intn(100) + 1
fmt.Println("n=", n)
count++
if(n == 50){
break //表示跳出for循环
}
}
fmt.Printf("生成50一共用了%d次", count)
}
案例②
通过break标签跳出指定循环
package main
import (
"fmt"
_"math/rand"
_ "go_code/project01/main/model"
)
func main(){
//通过标签跳出指定循环
label2:
for i:= 0; i < 4; i++ {
//label 设置标签,当然用其他也可以设置,如:abc
for j:= 0; j < 3; j++ {
if j == 2 {
break label2
}
fmt.Println("j=", j) // 0 1
}
}
}
1.3.3 continue继续
continue 语句用于结束本次循环,继续执行下一次循环
- continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的 break 标签的使用的规则一样.
案例:
从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为 0 时结束程序
package main
import (
"fmt"
_"math/rand"
_ "go_code/project01/main/model"
)
func main(){
var positiveCount int //正数个数
var negativeCount int //负数个数
var num int
for{
fmt.Println("请输入一个整数:")
fmt.Scanln(&num)
if num == 0 {
break //跳出循环
}
if num > 0 {
positiveCount++
continue //结束本次循环,进入下次循环
}
negativeCount++
}
fmt.Printf("负数个数为:%v", negativeCount)
fmt.Printf("正数个数为:%v", positiveCount)
}
1.4 跳转控制语句goto
- Go 语言的 goto 语句可以无条件地转移到程序中指定的行。
- goto 语句通常与条件语句配合使用。可用来实现条件转移,跳出循环体等功能。
- 在 Go 程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难
func main(){
var n int = 30
//演示goto的使用
fmt.Println("ok1")
if n > 20 {
goto label1
}
fmt.Println("ok2")
fmt.Println("ok3")
label1:
fmt.Println("ok~")
fmt.Println("ok~~~~~")
//ok1
// ok~
// ok~~~~~
}
1.5 跳转控制语句return
return 使用在方法或者函数中,表示跳出所在的方法或函数
- 如果 return 是在普通的函数,则表示跳出该函数,即不再执行函数中 return 后面代码,也可以理解成终止函数。
- 如果 return 是在 main 函数,表示终止 main 函数,也就是说终止程序。
func main(){
var count int = 3
for {
if count == 0 {
return
}
count--
fmt.Println("lala", count)
}
}
上述代码直接终止main函数
二、函数、包
2.1 函数
为完成某一功能的程序指令(语句)的集合,称为函数。
- 在 Go 中,函数分为: 自定义函数、系统函数
- 函数,方便反复使用,方便代码维护
特点:
- 如果返回多个值时,在接收时,希望忽略某个返回值,则使用
_
符号占位忽略- 如果返回值只有一个,(返回值类型列表)可以不写()
- 函数的形参列表可以是多个,返回值列表也可以是多个
- 形参列表和返回值列表的数据类型可以是:值类型和引用类型
- 函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本包文件和其它包文件使用,类似 public , 首字母小写,只能被本包文件使用,其它包文件不能使用,类似 private
- 如果希望函数内的变量能修改函数外的变量(指的是默认以值传递的方式的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量。从效果上看类似引用 。
- Go的函数不支持函数重载【方法名相同,参数列表排列组合不同】
- Go 中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用
- Go函数既然是一种数据类型,因此在Go中,函数可以作为形参进行调用
- 为了简化数据类型定义,Go支持自定义类型
基本语法:type 自定义数据类型名 数据类型 // 理解: 相当于一个别名案例:type myInt int // 这时 myInt 就等价 int 来使用了.
- Go支持可变参数
2.2 包
- 包的定义:
包的本质实际上就是创建不同的文件夹,来存放程序文件。
- 说明:go 的每一个文件都是属于一个包的,也就是说 go 是以包的形式来管理文件和项目目录结构
- 打包: package 包名
- 引入包: import 包名
-
包的作用:
- 区分相同名字的函数、变量等标识符
- 当程序文件很多时,可以很好的管理项目控制函数、变量等访问范围,即作用域
-
包的注意事项:
- 在给一个文件打包时,该包对应一个文件夹,比如这里的 utils 文件夹对应的包名就是 utils,
文件的包名通常和文件所在的文件夹名一致,一般为小写字母。- 当一个文件要使用其它包函数或变量时,需要先引入对应的包
- 引入方式 1:import “包名”
- 引入方式 2: import (
“包名”
“包名”
)- package 指令在 文件第一行,然后是 import 指令。
- 在 import 包时,路径从 $GOPATH 的 src 下开始,不用带 src , 编译器会自动从 src 下开始引入
- 为了让其它包的文件,可以访问到本包的函数,则该函数名的首字母需要大写,类似其它语言的 public ,这样才能跨包访问。比如 utils.go
- 在访问其它包函数,变量时,其语法是 包名.函数名
- 如果包名较长,Go 支持给包取别名, 注意细节:取别名后,原来的包名就不能使用了【如果给包取了别名,则需要使用别名来访问该包的函数和变量】
- 在同一包下,不能有相同的函数名(也不能有相同的全局变量名),否则报重复定义
如果你要编译成一个可执行程序文件,就需要将这个包声明为 main , 即 package main .这个就是一个语法规范,如果你是写一个库 ,包名可以自定义
2.3 综合案例
在util文件夹下定义一个工具类,用于求两数之和,并在hello.go中引入util包使用GetSum函数
项目结构:
util.go:
package utils
//公共变量【首字母大写】
var Address string = "北京"
//定义一个函数
func GetSum(num1 int, num2 int) int {
return num1 + num2
}
hello.go:
package main
import (
"fmt"
u "go_code/project01/main/util" //起别名
_ "go_code/project01/main/model" //不使用model下的
)
func main(){
sum := u.GetSum(10, 20)
fmt.Println("sum=", sum)
fmt.Printf("address=%v", u.Address)
//sum= 30
//address=北京
}
2.4 init、匿名函数
2.4.1 init函数
①定义
每一个源文件都可以包含一个 init 函数,该函数会在 main 函数执行前,被 Go 运行框架调用,也就是说 init 会在 main 函数前被调用。
package main
import (
"fmt"
)
func init(){
fmt.Println("init run....")
}
func main(){
fmt.Println("main run....")
}
//init run....
//main run....
②注意事项
init 函数最主要的作用,就是完成一些初始化的工作
- 细节说明: 面试题:案例如果 main.go 和 utils.go 都含有 变量定义,init 函数时,执行的流程又是怎么样的呢?
2.4.2 匿名函数
Go 支持匿名函数,匿名函数就是没有名字的函数,如果我们某个函数只是希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用。
使用方式:
方式一:在定义匿名函数时就直接调用,这种方式匿名函数只能调用一次。
package main
import (
"fmt"
)
func main(){
//在定义匿名函数时就直接调用,这种方式匿名函数只能调用一次
res := func (num1 int, num2 int) int {
return num1 + num2
}(10, 20)
//res= 30
fmt.Println("res=", res)
}
方式二:将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数
func main(){
//在定义匿名函数时就直接调用,这种方式匿名函数只能调用一次
f := func (num1 int, num2 int) int {
return num1 + num2
}
res := f(10, 15)
fmt.Println("res=", res)
}
方式三:全局匿名函数。如果将匿名函数赋给一个全局变量,那么这个匿名函数,就成为一个全局匿名函数,可以在程序有效。
package main
import (
"fmt"
)
var (
//Fun1就是一个全局匿名函数
Fun1 = func(num1 int, num2 int) int {
return num1 + num2
}
)
func main(){
//全局匿名函数的使用
res := Fun1(20, 30)
//res= 50
fmt.Println("res=", res)
}
2.5 闭包
2.5.1 介绍
基本介绍:闭包就是一个函数和与其相关的引用环境组合的一个整体(实体)
对上面代码的说明和总结
- AddUpper 是一个函数,返回的数据类型是 fun (int) int
- 闭包的说明
返回的是一个匿名函数, 但是这个匿名函数引用到函数外的n ,因此这个匿名函数就和n 形成一个整体,构成闭包。 - 大家可以这样理解: 闭包是类, 函数是操作,n 是字段。函数和它使用到 n 构成闭包。
- 当我们反复的调用 f 函数时,因为 n 是初始化一次,因此每调用一次就进行累计。
- 我们要搞清楚闭包的关键,就是要分析出返回的函数它使用(引用)到哪些变量,因为函数和它引用到的变量共同构成闭包。
- 对上面代码的一个修改,加深对闭包的理解
package main
import (
"fmt"
)
//累加器
//闭包:【初始化后,环境就一份】,前面的调用执行会影响到后面
func AddUpper() func (int) int {
var n int = 10
var str = "hello"
return func (x int) int {
n = n + x
str += string(36) // ascii中36对应是'$'
fmt.Println("str=", str) // 1. str="hello$" 2. str="hello$$" 3. str="hello$$$"
return n
}
}
func main(){
//使用前面的累加器
f := AddUpper();
fmt.Println(f(1)); //11
fmt.Println(f(2)); //13
fmt.Println(f(3)); //16
}
2.6 defer(延时)
在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等) ,为了在函数执行完毕后,及时的释放资源,Go 的设计者提供 defer (延时机制)。
案例:
package main
import (
"fmt"
)
func sum (n1 int, n2 int) int {
//当执行到defer时,暂不执行,会将defer后面的语句压入到独立的栈(defer栈)
//当函数执行完毕后,再从defer栈中,按照先入后出的方式出栈执行
defer fmt.Println("ok1 n1=", n1)// defer 3. ok1 n1 = 10
defer fmt.Println("ok2 n2=", n2)// defer 2. ok2 n2 = 20
res := n1+n2 //res=30
fmt.Println("ok3, res=", res) //1. ok3 res=30
return res
}
func main(){
res := sum(10, 20)
fmt.Println("res=", res) //4. res=30
}
执行结果:
注意事项:
- 当 go 执行到一个 defer 时,不会立即执行 defer 后的语句,而是将 defer 后的语句压入到一个栈中[我为了讲课方便,暂时称该栈为 defer 栈], 然后继续执行函数下一个语句。
- 当函数执行完毕后,在从 defer 栈中,依次从栈顶取出语句执行(注:遵守栈 先入后出的机制),
- 在 defer 将语句放入到栈时,也会将相关的值拷贝同时入栈。
输出结果如下:
defer 最主要的价值是在,当函数执行完毕后,可以及时的释放函数创建的资源。
- 在 golang 编程中的通常做法是,创建资源后,比如(打开了文件,获取了数据库的链接,或者是锁资源), 可以执行 defer file.Close() defer connect.Close()
- 在 defer 后,可以继续使用创建资源.
- 当函数完毕后,系统会依次从 defer 栈中,取出语句,关闭资源.
- 这种机制,非常简洁,程序员不用再为在什么时机关闭资源而烦心。
2.7 函数参数传递方式及字符串常用系统函数
2.7.1 传参方式
- 值类型参数默认就是值传递,而引用类型参数默认就是引用传递。
- 管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。
- 值类型:基本数据类型 int 系列, float 系列, bool, string 、数组和结构体 struct
- 引用类型:指针、slice 切片、map、管道 chan、interface 等都是引用类型
2.7.2 字符串常用系统参数
- 统计字符串长度
len(str)
func main(){
var str string = "china中国"
//在go语言中默认编码使用utf-8编码,字母数字占1字节,中文占3字节
//11
fmt.Println(len(str))
}
- 带中文字符串遍历
r := []rune(str)
func main(){
str := "hello北京"
//字符遍历,同时处理有中文问题时, r := []rune(str)
arr := []rune(str)
for i := 0; i < len(arr); i++{
fmt.Printf("字符=%c\n", arr[i])
}
}
- 字符串转整数
n, err := strconv.Atoi(“12”)
import (
"fmt"
"strconv"
)
func main(){
//字符串转整数: n, err := strconv.Atoi(str)
str := "hello"
n, err := strconv.Atoi(str)
if err != nil {
fmt.Println("转换错误:", err)
}else{
fmt.Println("转换结果是:", n)
}
}
- 整数转字符串
str = strconv.Itoa(12345)
package main
import (
"fmt"
"strconv"
)
func main(){
//str = strconv.Itoa(1234)
str := strconv.Itoa(1234)
//str=1234, 类型为:string
fmt.Printf("str=%v, 类型为:%T", str, str)
}
- 字符串转[]byte
var bytes = []byte(“hello go”)
package main
import (
"fmt"
_ "strconv"
)
func main(){
//字符串转[]byte: var bytes = []byte("hello go")
var bytes = []byte("hello go")
//bytes=[104 101 108 108 111 32 103 111]
fmt.Printf("bytes=%v\n", bytes)
}
- []byte转字符串
str = string([]byte{97, 98, 99})
func main(){
//[]byte 转字符串: str = string([]byte{97, 98, 99})
str := string([]byte{97, 98, 99})
//str=abc
fmt.Printf("str=%v\n", str)
}
- 进制转换
str = strconv.FormatInt(123, 2)
package main
import (
"fmt"
"strconv"
)
func main(){
//10进制转2, 8, 16进制: str = strconv.FormatInt(123, 2), 返回对应的字符串
str := strconv.FormatInt(123, 2)
fmt.Printf("123对应的二进制是=%v\n", str)
str = strconv.FormatInt(123, 16)
fmt.Printf("123对应的十六进制是=%v\n", str)
//123对应的二进制是=1111011
//123对应的十六进制是=7b
}
- 是否包含字串
strings.Contains(“seafood”, “foo”) //true
package main
import (
"fmt"
_ "strconv"
"strings"
)
func main(){
//查找子串是否在指定的字符串中 strings.Contatins("seafood", "foo")
b := strings.Contains("seafood", "foo")
//b=true
fmt.Printf("b=%v\n", b)
}
- 统计包含几个指定的子串
strings.Count(“ceheese”, “e”)
package main
import (
"fmt"
"strings"
)
func main(){
num := strings.Count("chinese", "e")
//num=2
fmt.Printf("num=%v\n", num)
}
- 比较字符串
不区分大小写的字符串比较(== 是区分字母大小写的): fmt.Println(strings.EqualFold(“abc”, “Abc”)) // true
import (
"fmt"
"strings"
)
func main(){
//不区分大小写
b := strings.EqualFold("abc", "Abc")
fmt.Printf("b=%v\n", b)
// == 区分大小写
fmt.Printf("结果=%v", "abc" == "Abc")
}
- 返回子串第一次出现的位置
返回子串在字符串第一次出现的 index 值,如果没有返回-1 : strings.Index(“NLT_abc”, “abc”) // 4
import (
"fmt"
"strings"
)
func main(){
//返回子串第一次出现的位置
index := strings.Index("ffrqw2432CBA", "CBA")
//index=9
fmt.Println("index=", index)
}
- 返回子串最后一次出现的位置
返回子串在字符串最后一次出现的 index,如没有返回-1 : strings.LastIndex(“go golang”, “go”)
func main(){
//返回子串最后一次出现的位置
index := strings.LastIndex("fCBAfrqwCBA2432CBA", "CBA")
//index= 15
fmt.Println("index=", index)
}
- 替换指定的子串
将指定的子串替换成 另外一个子串: strings.Replace(“go go hello”, “go”, “go 语言”, n) n 可以指定你希望替换几个,如果 n=-1 表示全部替换
func main(){
//替换指定字符串,n=-1表示全部替换[替换不会影响原来的值]
str := "go go go hello"
str2 := strings.Replace(str, "go", "北京", 2)
//str=go go go hello
//str2=北京 北京 go hello
fmt.Printf("str=%v\nstr2=%v", str, str2)
}
- 按照指定字符分割
按 照 指 定 的 某 个 字 符 , 为 分 割 标 识 , 将 一 个 字 符 串 拆 分 成 字 符 串 数 组 :
strings.Split(“hello,wrold,ok”, “,”)
func main(){
//按照指定字符分割
strArr := strings.Split("hello, world, ok", ",")
for i := 0; i < len(strArr); i++ {
fmt.Printf("str[%v]=%v\n", i, strArr[i])
}
// str[0]=hello
// str[1]= world
// str[2]= ok
// strArr=[hello world ok]
fmt.Printf("strArr=%v", strArr)
}
- 将字符串的字母进行大小写转换
将字符串的字母进行大小写的转换: strings.ToLower(“Go”) // go strings.ToUpper(“Go”) // GO
func main(){
//将字母按照大小写进行转换
//strings.ToLower("Go") strings.ToUpper("Go")
str := "goLang Hello"
str = strings.ToLower(str)
// str=golang hello
fmt.Printf("str=%v\n", str)
str = strings.ToUpper(str)
//str=GOLANG HELLO
fmt.Printf("str=%v\n", str)
}
- 去掉字符串左右两边的空格
将字符串左右两边的空格去掉: strings.TrimSpace(" tn a lone gopher ntrn ")
func main(){
//去掉字符串左右两边的空格
str := strings.TrimSpace(" longer tor fad ")
// str=longer tor fad
fmt.Printf("str=%v\n", str)
}
- 去掉字符串左右两边指定的字符
将字符串左右两边指定的字符去掉 : strings.Trim("! hello! “, " !”) // [“hello”] //将左右两边 !和 " "去掉
func main(){
//去掉字符串左右两边指定的字符串
str := strings.Trim("!!hello!!!hello!!!", "!")
//str=hello!!!hello
fmt.Printf("str=%v\n", str)
}
- 去掉字符串左边指定的字符
将字符串左边指定的字符去掉 : strings.TrimLeft("! hello! “, " !”) // [“hello”] //将左边 ! 和 " "去掉
package main
import (
"fmt"
"strings"
)
var (
str string
)
func main(){
str = "!hello!!!"
str = strings.TrimLeft(str, "!")
//str=hello!!!
fmt.Printf("str=%v", str)
}
- 去掉字符串右边指定的字符
将字符串右边指定的字符去掉 : strings.TrimRight("! hello! “, " !”) // [“hello”] //将右边 ! 和 " "去掉
func main(){
str := "!hello!!!"
str = strings.TrimRight(str, "!")
//str=!hello
fmt.Printf("str=%v", str)
}
- 判断字符串是否以指定字符开头
判断字符串是否以指定的字符串开头: strings.HasPrefix(“ftp://192.168.10.1”, “ftp”) // true
func main(){
str := "miss you very much"
b := strings.HasPrefix(str, "miss")
//b=true
fmt.Printf("b=%v", b)
}
- 判断字符串是否以指定字符结束
判断字符串是否以指定的字符串结束: strings.HasSuffix(“NLT_abc.jpg”, “abc”) //false
func main(){
str := "miss you very much"
b := strings.HasSuffix(str, "ch")
//b=true
fmt.Printf("b=%v", b)
}
2.8 时间和日期相关函数
1)时间和日期相关函数,需要导入 time 包
2) time.Time 类型,用于表示时间
func main(){
//获取当前时间
now := time.Now()
fmt.Printf("now=%v now type=%T", now, now)
}
3)如何获取到其他日期的信息
import (
"fmt"
"time"
)
func main(){
//1. 获取当前时间
now := time.Now()
fmt.Printf("now=%v now type=%T\n", now, now)
//2. 通过now可以获取到年月日, 时分秒
fmt.Printf("年=%v\n", now.Year())
fmt.Printf("月=%v\n", now.Month())
// fmt.Printf("月=%v\n", int(now.Month())) //月=4
fmt.Printf("日=%v\n", now.Day())
fmt.Printf("时=%v\n", now.Hour())
fmt.Printf("分=%v\n", now.Minute())
fmt.Printf("秒=%v\n", now.Second())
}
4)格式化日期时间
方式 1: 就是使用 Printf 或者 SPrintf
import (
"fmt"
"time"
)
func main(){
//格式化日期时间
now := time.Now()
fmt.Printf("当前年月日 %d-%d-%d %d:%d:%d\n",
now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
dateStr := fmt.Sprintf("当前年月日 %d-%d-%d %d:%d:%d\n",
now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
fmt.Printf("dateStr=%v\n", dateStr)
//当前年月日 2023-4-28 14:18:22
//dateStr=当前年月日 2023-4-28 14:18:22
}
方式二: 使用 time.Format() 方法完成:
func main(){
now := time.Now()
//格式化日期时间的第二种方式Format必须传入:2006-01-02 15:04:05
fmt.Printf(now.Format("2006-01-02 15:04:05"))
fmt.Println()
fmt.Printf(now.Format("2006-01-02"))
fmt.Println()
fmt.Printf(now.Format("15:04:05"))
// 2023-04-28 14:22:14
// 2023-04-28
// 14:22:14
}
对上面代码的说明:
“2006/01/02 15:04:05” 这个字符串的各个数字是固定的,必须是这样写。
“2006/01/02 15:04:05” 这个字符串各个数字可以自由的组合,这样可以按程序需求来返回时间和日期
- 时间的常量
const (
Nanosecond Duration = 1 //纳秒
Microsecond = 1000 * Nanosecond //微秒
Millisecond = 1000 * Microsecond //毫秒Second = 1000 * Millisecond //秒
Minute = 60 * Second //分钟
Hour = 60 * Minute //小时
)
常量的作用:在程序中可用于获取指定时间单位的时间,比如想得到 100 毫秒
100 * time. Millisecond
- 结合 Sleep 来使用一下时间常量
import (
"fmt"
"time"
)
func main(){
//需求:每隔1秒打印一个数字,打印到20就退出
i := 0
for{
i++
fmt.Println(i)
//ms * 100 = s
time.Sleep(time.Millisecond * 100)
if i == 20 {
break
}
}
}
- time 的 Unix 和 UnixNano 的方法
import (
"fmt"
"time"
)
func main(){
now := time.Now()
//Unix和UnixNano的使用
//unix时间戳=1682663062 unixnano时间戳=1682663062484601900
fmt.Printf("unix时间戳=%v unixnano时间戳=%v\n", now.Unix(), now.UnixNano())
}
结果是:
2.9 内置函数
Golang 设计者为了编程方便,提供了一些函数,这些函数可以直接使用,我们称为 Go 的内置函数。文档:https://studygolang.com/pkgdoc -> builtin
- len:用来求长度,比如 string、array、slice、map、channel
- new:用来分配内存,主要用来分配值类型,比如 int、float32,struct…返回的是指针举例说明 new 的使用:
上面代码对应的内存分析图:
- make:用来分配内存,主要用来分配引用类型,比如 channel、map、slice。