3 程序流程控制-函数、包、常用函数【Go语言教程】

news2024/11/26 16:22:52

3 程序流程控制-函数、包【Go语言教程】

一、 程序流程控制

  1. 顺序控制
  2. 分支控制
  3. switch分支
  4. 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
}

使用场景区分:

  1. 判断的具体数值不多,而且符合整数、浮点数、字符、字符串这几种类型。建议使用 swtich语句,简洁高效。
  2. 其他情况:对区间判断和结果为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

  1. Go 语言的 goto 语句可以无条件地转移到程序中指定的行。
  2. goto 语句通常与条件语句配合使用。可用来实现条件转移,跳出循环体等功能。
  3. 在 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 使用在方法或者函数中,表示跳出所在的方法或函数

  1. 如果 return 是在普通的函数,则表示跳出该函数,即不再执行函数中 return 后面代码,也可以理解成终止函数。
  2. 如果 return 是在 main 函数,表示终止 main 函数,也就是说终止程序。
func main(){
	var count int = 3
	for {
		if count == 0 {
			return
		}
		count--
		fmt.Println("lala", count)
	}
}

上述代码直接终止main函数

二、函数、包

2.1 函数

为完成某一功能的程序指令(语句)的集合,称为函数。

  • 在 Go 中,函数分为: 自定义函数、系统函数
  • 函数,方便反复使用,方便代码维护

在这里插入图片描述

特点:

  1. 如果返回多个值时,在接收时,希望忽略某个返回值,则使用_符号占位忽略
  2. 如果返回值只有一个,(返回值类型列表)可以不写()
  3. 函数的形参列表可以是多个,返回值列表也可以是多个
  4. 形参列表和返回值列表的数据类型可以是:值类型和引用类型
  5. 函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本包文件和其它包文件使用,类似 public , 首字母小写,只能被本包文件使用,其它包文件不能使用,类似 private
  6. 如果希望函数内的变量能修改函数外的变量(指的是默认以值传递的方式的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量。从效果上看类似引用 。
    在这里插入图片描述
  1. Go的函数不支持函数重载【方法名相同,参数列表排列组合不同】
  2. Go 中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用
    在这里插入图片描述
  1. Go函数既然是一种数据类型,因此在Go中,函数可以作为形参进行调用
  2. 为了简化数据类型定义,Go支持自定义类型
    基本语法:type 自定义数据类型名 数据类型 // 理解: 相当于一个别名案例:type myInt int // 这时 myInt 就等价 int 来使用了.
    在这里插入图片描述
  3. Go支持可变参数
    在这里插入图片描述

2.2 包

  • 包的定义:

包的本质实际上就是创建不同的文件夹,来存放程序文件。

  • 说明:go 的每一个文件都是属于一个包的,也就是说 go 是以包的形式来管理文件和项目目录结构
  • 打包: package 包名
  • 引入包: import 包名
  • 包的作用:

    • 区分相同名字的函数、变量等标识符
    • 当程序文件很多时,可以很好的管理项目控制函数、变量等访问范围,即作用域
  • 包的注意事项:

  1. 在给一个文件打包时,该包对应一个文件夹,比如这里的 utils 文件夹对应的包名就是 utils,
    文件的包名通常和文件所在的文件夹名一致,一般为小写字母。
  2. 当一个文件要使用其它包函数或变量时,需要先引入对应的包
  • 引入方式 1:import “包名”
  • 引入方式 2: import (
    “包名”
    “包名”
    )
  • package 指令在 文件第一行,然后是 import 指令。
  • 在 import 包时,路径从 $GOPATH 的 src 下开始,不用带 src , 编译器会自动从 src 下开始引入
  1. 为了让其它包的文件,可以访问到本包的函数,则该函数名的首字母需要大写,类似其它语言的 public ,这样才能跨包访问。比如 utils.go
  1. 在访问其它包函数,变量时,其语法是 包名.函数名
  2. 如果包名较长,Go 支持给包取别名, 注意细节:取别名后,原来的包名就不能使用了【如果给包取了别名,则需要使用别名来访问该包的函数和变量】
  3. 在同一包下,不能有相同的函数名(也不能有相同的全局变量名),否则报重复定义
    如果你要编译成一个可执行程序文件,就需要将这个包声明为 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 函数最主要的作用,就是完成一些初始化的工作
在这里插入图片描述

  1. 细节说明: 面试题:案例如果 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 介绍

基本介绍:闭包就是一个函数和与其相关的引用环境组合的一个整体(实体)

在这里插入图片描述

对上面代码的说明和总结

  1. AddUpper 是一个函数,返回的数据类型是 fun (int) int
  2. 闭包的说明
    在这里插入图片描述
    返回的是一个匿名函数, 但是这个匿名函数引用到函数外的n ,因此这个匿名函数就和n 形成一个整体,构成闭包。
  3. 大家可以这样理解: 闭包是类, 函数是操作,n 是字段。函数和它使用到 n 构成闭包。
  4. 当我们反复的调用 f 函数时,因为 n 是初始化一次,因此每调用一次就进行累计。
  5. 我们要搞清楚闭包的关键,就是要分析出返回的函数它使用(引用)到哪些变量,因为函数和它引用到的变量共同构成闭包。
  6. 对上面代码的一个修改,加深对闭包的理解
    在这里插入图片描述
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
}

执行结果:
在这里插入图片描述
注意事项:

  1. 当 go 执行到一个 defer 时,不会立即执行 defer 后的语句,而是将 defer 后的语句压入到一个栈中[我为了讲课方便,暂时称该栈为 defer 栈], 然后继续执行函数下一个语句。
  2. 当函数执行完毕后,在从 defer 栈中,依次从栈顶取出语句执行(注:遵守栈 先入后出的机制),
  3. 在 defer 将语句放入到栈时,也会将相关的值拷贝同时入栈。
    在这里插入图片描述
    输出结果如下:
    在这里插入图片描述

defer 最主要的价值是在,当函数执行完毕后,可以及时的释放函数创建的资源。

在这里插入图片描述

  1. 在 golang 编程中的通常做法是,创建资源后,比如(打开了文件,获取了数据库的链接,或者是锁资源), 可以执行 defer file.Close() defer connect.Close()
  2. 在 defer 后,可以继续使用创建资源.
  3. 当函数完毕后,系统会依次从 defer 栈中,取出语句,关闭资源.
  4. 这种机制,非常简洁,程序员不用再为在什么时机关闭资源而烦心。

2.7 函数参数传递方式及字符串常用系统函数

2.7.1 传参方式

  • 值类型参数默认就是值传递,而引用类型参数默认就是引用传递。
  • 管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。
  1. 值类型:基本数据类型 int 系列, float 系列, bool, string 、数组和结构体 struct
  2. 引用类型:指针、slice 切片、map、管道 chan、interface 等都是引用类型

在这里插入图片描述

2.7.2 字符串常用系统参数

  1. 统计字符串长度

len(str)

func main(){
	var str string = "china中国"
	//在go语言中默认编码使用utf-8编码,字母数字占1字节,中文占3字节
	//11
	fmt.Println(len(str))
}
  1. 带中文字符串遍历

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])
	}
}
  1. 字符串转整数

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)
	}
}
  1. 整数转字符串

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)
}
  1. 字符串转[]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)
}
  1. []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)
}
  1. 进制转换

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
}
  1. 是否包含字串

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)
}
  1. 统计包含几个指定的子串

strings.Count(“ceheese”, “e”)

package main
import (
	"fmt"
	"strings"
)

func main(){
	num := strings.Count("chinese", "e")
	//num=2
	fmt.Printf("num=%v\n", num)
}
  1. 比较字符串

不区分大小写的字符串比较(== 是区分字母大小写的): 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")
}
  1. 返回子串第一次出现的位置

返回子串在字符串第一次出现的 index 值,如果没有返回-1 : strings.Index(“NLT_abc”, “abc”) // 4

import (
	"fmt"
	"strings"
)

func main(){
	//返回子串第一次出现的位置
	index := strings.Index("ffrqw2432CBA", "CBA")
	//index=9
	fmt.Println("index=", index)
}
  1. 返回子串最后一次出现的位置

返回子串在字符串最后一次出现的 index,如没有返回-1 : strings.LastIndex(“go golang”, “go”)

func main(){
	//返回子串最后一次出现的位置
	index := strings.LastIndex("fCBAfrqwCBA2432CBA", "CBA")
	//index= 15
	fmt.Println("index=", index)
}
  1. 替换指定的子串

将指定的子串替换成 另外一个子串: 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)
}
  1. 按照指定字符分割

按 照 指 定 的 某 个 字 符 , 为 分 割 标 识 , 将 一 个 字 符 串 拆 分 成 字 符 串 数 组 :
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)
}
  1. 将字符串的字母进行大小写转换

将字符串的字母进行大小写的转换: 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)
}
  1. 去掉字符串左右两边的空格

将字符串左右两边的空格去掉: 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)
}
  1. 去掉字符串左右两边指定的字符

将字符串左右两边指定的字符去掉 : strings.Trim("! hello! “, " !”) // [“hello”] //将左右两边 !和 " "去掉

func main(){
	//去掉字符串左右两边指定的字符串
	str := strings.Trim("!!hello!!!hello!!!", "!")
	//str=hello!!!hello
	fmt.Printf("str=%v\n", str)
}
  1. 去掉字符串左边指定的字符

将字符串左边指定的字符去掉 : 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)
}
  1. 去掉字符串右边指定的字符

将字符串右边指定的字符去掉 : strings.TrimRight("! hello! “, " !”) // [“hello”] //将右边 ! 和 " "去掉

func main(){
	str := "!hello!!!"
	str = strings.TrimRight(str, "!")
	//str=!hello
	fmt.Printf("str=%v", str)
}
  1. 判断字符串是否以指定字符开头

判断字符串是否以指定的字符串开头: 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)
}
  1. 判断字符串是否以指定字符结束

判断字符串是否以指定的字符串结束: 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” 这个字符串各个数字可以自由的组合,这样可以按程序需求来返回时间和日期

  1. 时间的常量
const (
Nanosecond	Duration = 1 //纳秒
Microsecond	= 1000 * Nanosecond	//微秒
Millisecond	= 1000 * Microsecond //毫秒Second		= 1000 * Millisecond //秒
Minute	= 60 * Second //分钟
Hour	= 60 * Minute //小时
)

常量的作用:在程序中可用于获取指定时间单位的时间,比如想得到 100 毫秒
100 * time. Millisecond

  1. 结合 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
		}
	}
}
  1. 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

  1. len:用来求长度,比如 string、array、slice、map、channel
  2. new:用来分配内存,主要用来分配值类型,比如 int、float32,struct…返回的是指针举例说明 new 的使用:
    在这里插入图片描述
    上面代码对应的内存分析图:
    在这里插入图片描述
  3. make:用来分配内存,主要用来分配引用类型,比如 channel、map、slice。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/471533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CVE-2023-28432 MiniO信息泄露漏洞复现

CVE-2023-28432 MiniO信息泄露漏洞 MiniO 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等 在集群部署的 Minio…

计算机网络学习05(HTTP vs HTTPS)

1、HTTP 协议介绍 HTTP 协议&#xff0c;全称超文本传输协议&#xff08;Hypertext Transfer Protocol&#xff09;。顾名思义&#xff0c;HTTP 协议就是用来规范超文本的传输&#xff0c;超文本&#xff0c;也就是网络上的包括文本在内的各式各样的消息&#xff0c;具体来说&…

【干货分享】一文说透分布式一致性协议(上)

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;大熊老师 | 慕课网讲师 在常见的分布式系统中&#xff0c;总会发生诸如机器宕机或网络异常&#xff08;包括消息的延迟…

ChatGPT实现多语种翻译

语言翻译 多语种翻译是 NLP 领域的经典话题&#xff0c;也是过去很多 AI 研究的热门领域。一般来说&#xff0c;我们认为主流语种的互译一定程度上属于传统 AI 已经能较好完成的任务。比如谷歌翻译所采用的的神经机器翻译(NMT, Neural Machine Translation)技术就一度让世人惊…

【JavaEE进阶】——第四节.Spring更简单的实现Bean对象的存取(利用注解储存和注入Bean对象)

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;JavaEE进阶 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目录 前…

Linux安装flutter

在Linux上安装flutter 1.使用快照安装flutter 安装snapd sudo apt update sudo apt install snapd安装flutter sudo snap install flutter --classic显示flutter sdk-path flutter sdk-path2.手动安装flutter 在flutter官网上查看安装流程 https://docs.flutter.dev/get…

现代微服务中缓存的分类及缓存一致性设计原则

引言 大部分面向公众的互联网系统&#xff0c;其并发请求数量与在线用户数量都是正相关的&#xff0c;而 MySQL能够承担的并发读写量是有一定上限的&#xff0c;当系统的访问量超过一定程度的时候&#xff0c;纯MySQL就很难应付了。 绝大多数互联网系统都是采用MySQLRedis这对…

MongoDB【索引-index】

目录 1&#xff1a;概述 2&#xff1a;索引的类型 2.1&#xff1a;单字段索引 2.2&#xff1a;复合索引 2.3&#xff1a;其他索引 3&#xff1a;索引的管理操作 3.1&#xff1a;索引的查看 3.2&#xff1a;索引的创建 3.3&#xff1a;索引的移除 4&#xff1a;索引的…

【福利赠书】有人说,测试驱动开发已死?(文末赠书3本)

友情推荐一本测试领域的教科书&#xff1a;&#xff08;文末送3本&#xff09; 《 测试驱动开发&#xff1a;入门、实战与进阶》&#xff0c;英文原书名为《Learning Test-Driven Development 》&#xff0c;是一本实用且有趣的TDD实践教程。如果你想开始做测试驱动开发&#x…

【WPF动画】简单构造一个相册轮播图淡化切换特效

效果图 简单的定时器结合DoubleAnimation使用示例&#xff0c;实现轮播图淡化切入特效 代码部分 <Image x:Name"carouselImage" Margin"10" HorizontalAlignment"Center" VerticalAlignment"Center" Stretch"UniformToFill&…

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析 倾斜摄影超大场景的三维模型的顶层合并需要对纹理进行压缩和抽稀处理&#xff0c;以减小数据量和提高数据的传输和展示性能。以下是一种常用的纹理压缩和抽稀处理技术&#xff1a; 1、纹理图集 纹理瓦片化…

网络安全漏洞分析之远程代码执行

介绍 Apache Flume 是一个分布式的&#xff0c;可靠的&#xff0c;并且可用于高效地收集&#xff0c;汇总和移动大量日志数据的软件。它具有基于流数据流的简单而灵活的体系结构。它具有可调的可靠性机制以及许多故障转移和恢复机制&#xff0c;并且具有健壮性和容错性。它使用…

国民技术N32G430开发笔记(9)- IAP升级 Bootloader的制作

IAP升级 Bootloader的制作 1、上节提到Flash的分区&#xff0c;0x8000000-0x8004000为Boot分区&#xff0c;我们的bootloader就烧录到此分区。 Bootloader很简单&#xff0c;新建一个普通的工程&#xff0c; 也不用初始化外部设备&#xff0c;开机后&#xff0c;直接跳转到 A…

【方法】 如何批量将RAR或其他压缩格式转换成ZIP?

压缩文件的格式有很多种&#xff0c;比如RAR、ZIP、7-Zip、CAB、ARJ、ACE、TAR、BZ2等等。因为需求不同&#xff0c;或者不同平台对上传的压缩包格式要求不同&#xff0c;我们往往需要把压缩文件进行格式转换&#xff0c;那压缩文件不同格式之间如何进行转换呢&#xff1f; 如…

AlgoC++第八课:手写BP

目录 手写BP前言1. 数据加载2. 前向传播3. 反向传播总结 手写BP 前言 手写AI推出的全新面向AI算法的C课程 Algo C&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考。 本次课程主要是手写 BP 代码 课程大纲可看下面的思维导图 1. 数据加载 我们首先来实现下MNIST…

15-721 Chapter10 恢复协议

BackGround 为了在可能crash的情况下&#xff0c;确保事务和数据库状态的&#xff0c;一致性&#xff0c;原子性&#xff0c;持久性。恢复算法大体可以分为两个方面&#xff1a;1.在事务过程中要做哪些处理 2.崩溃后要做哪些处理。 与disk数据库的差异 1.恢复不需要跟踪dir…

独立IP服务器和共享IP服务器有什么区别

在选择一个合适的服务器时&#xff0c;最常见的选择是共享IP服务器和独立IP服务器。尽管两者看起来很相似&#xff0c;但它们有着很大的不同。本文将详细介绍共享IP服务器和独立IP服务器的不同之处&#xff0c;以及如何选择适合您需求的服务器。 一、什么是共享IP服务器? 共享…

PHPStudy hosts文件可能不存在或被阻止打开,同步hosts失败

在使用PHPStudy建站包时&#xff0c;有时会遇到同步hosts失败的问题&#xff0c;可能是因为hosts文件不存在或被阻止打开。这个问题通常可以通过以下几个步骤解决&#xff1a; 步骤一&#xff1a;检查hosts文件是否存在 首先&#xff0c;我们需要检查一下hosts文件是否存在。…

【漏洞复现】海康威视综合安防管理平台Fastjson远程命令执行漏洞复现

文章目录 前言声明一、海康威视综合安防管理平台简介二、漏洞描述三、影响版本四、漏洞复现五、修复方案 前言 ​海康威视综合安防管理平台存在Fastjson远程命令执行漏洞&#xff0c;攻击者可通过构造恶意Payload执行并获取服务器系统权限以及敏感数据信息。 声明 本篇文章仅…

计算机网络学习07(DNS域名系统详解)

DNS&#xff08;Domain Name System&#xff09;域名管理系统&#xff0c;是当用户使用浏览器访问网址之后&#xff0c;使用的第一个重要协议。DNS 要解决的是域名和 IP 地址的映射问题。 在实际使用中&#xff0c;有一种情况下&#xff0c;浏览器是可以不必动用 DNS 就可以获知…