极速Go语言入门(超全超详细)-基础篇2

news2025/7/13 22:58:01

文章目录

      • 函数进阶
      • 结构体
      • 接口
      • 继承
      • type
      • 值类型与引用类型
      • 值传递、引用传递
      • 打包、引用包
        • 工具类打包文件代码
        • 引用包代码
      • 方法
      • 异常捕捉处理
      • 字符串常用函数
      • 日期常用函数
      • 管道(channel)

书接上篇:极速Go语言入门(超全超详细)-基础篇

整个基础篇合计32000字左右,如有遗漏可以私信我进行补充

函数进阶

以下展示函数return的使用、普通函数、匿名函数、闭包、defer延迟执行、函数作为参数传递、函数作为函数返回值、内置函数

go内置函数可参考: 中文官方文档中**builtin**(点击跳转)一栏

示例代码

package main

import (
	"fmt"
	"strconv"
)

func main() {
		println("-------return测试---------")
	result_1, result_2 := returnTest(88, 99)
	result_3, result_4 := returnTestV2(88, 99)
	fmt.Printf("returnTest执行结果, result_1 = %v, result_2 = %v \n", result_1, result_2)
	fmt.Printf("returnTestV2执行结果, result_3 = %v, result_4 = %v \n", result_3, result_4)

	println("-------函数测试---------")
	testFuntion(1)
	funcResultV2_1, funcResultV2_2 := testFuntionV2(1, "123")
	fmt.Printf("funcResultV2_1 = %v, funcResultV2_2 = %v \n", funcResultV2_1, funcResultV2_2)
	testFuntionV3()
	testFuntionV3(1, 2, 3, 4, 5)
	println("-------匿名函数测试---------")
	//匿名函数,没有名字的函数,放在代码块中直接执行
	anonymousFuncResult_1, _ := func(n1 int, n2 int) (int, float64) {
		return n1 * n2, float64(n1 * n2)
	}(2, 8) //尾部的括号里传递参数

	fmt.Println("anonymousFuncResult = ", anonymousFuncResult_1)
	//也可以直接把匿名函数赋值给变量,但是赋值给变量之前不能给匿名函数传递参数
	a := func(n1 int, n2 int) (int, int) {
		return n2, n1
	} //尾部没有参数

	n1 := 10
	n2 := 29
	n1, n2 = a(n1, n2)
	fmt.Printf("匿名函数赋值给变量之后n1 = %v, n2 = %v \n", n1, n2)

	println("-------全局匿名函数测试---------")
	//调用定义好的匿名函数全局变量
	globalVariableFuncResult_1, globalVariableFuncResult_2 := globalVariableFunc(1, 3)
	fmt.Printf("调用全局匿名函数结果globalVariableFuncResult_1 = %v type: %T, globalVariableFuncResult_1 = %v type: %T\n",
		globalVariableFuncResult_1, globalVariableFuncResult_1, globalVariableFuncResult_2, globalVariableFuncResult_2)
	//闭包调用
	f2 := closureTest()
	//依下述输出来看,虽然我们没有显性的声明一个全局变量,但是我们每次调用都会进行累加
	fmt.Printf("闭包调用第1次返回结果:%v \n", f2(10))
	fmt.Printf("闭包调用第2次返回结果:%v \n", f2(10))
	fmt.Printf("闭包调用第3次返回结果:%v \n", f2(10))
	f3 := closureTest()
	fmt.Printf("新的闭包调用第1次返回结果:%v \n", f3(10)) //新的实例运行后并不会原先闭包函数中的变量

	println("-------defer测试---------")
	//defer:defer是go中一种延迟调用机制,defer后面的函数只有在当前函数执行完毕后才能执行,通常用于释放资源。
	//参考资料:https://blog.csdn.net/m0_46251547/article/details/123762669
	deferTest("字符参数")

	println("-------函数作为参数测试---------")
	testFuncArg(printString)

	println("-------函数作为返回值测试---------")
	returnFunc := testReturnFunc()
	fmt.Printf("函数作为返回值测试, 返回结果类型 = %T \n", returnFunc)
	finalResult := returnFunc(100, 200)
	fmt.Printf("执行函数, 结果 = %d, 类型 = %T \n", finalResult, finalResult)

	println("-------内置函数测试---------")
	//1. len : 用来求长度,比如string、array、slice、map、channel
	//2. new : 用来分配内存,主要用来分配值类型,比如int、float32、struct…返回的是指针
	//3. make:用来分配内存,主要用来分配引用类型,比如chan、map、slice。
	//值类型的用new,返回的是一个指针
	p := new(int)
	fmt.Println("*p = ", *p, ", p = ", p)
	*p = 29
	fmt.Println("*p = ", *p)
	//引用类型的用make
	stringStringMap := make(map[string]string, 10)
	//向map增加元素
	stringStringMap["name"] = "Mir Li"
	stringStringMap["age"] = "18"


}

/**   如下所示,函数定义
func 函数名 (参数列表) (返回值列表) { //返回值只有一个时可以不写()

	//函数体,功能执行
	return 返回值列表

}
*/
// ///return///
func returnTest(n1 int64, n2 int64) (string, int64) {
	//return:用于函数执行结果的值返回,可以返回一个或者多个参数
	result_1 := strconv.FormatInt(n1*n2, 10)
	result_2 := n1 + n2
	return result_1, result_2
}

// 上面的写法还可以这些写
func returnTestV2(n1 int64, n2 int64) (result_1 string, result_2 int64) {
	result_1 = strconv.FormatInt(n1*n2, 10)
	result_2 = n1 + n2
	return
}

// //普通函数//
// 单个入参、单个出参
func testFuntion(number int) int { //()里的是入参, {左边的是返回值类型和参数, 可以写(result, int)
	return number * 10
}

func testFuntionV2(number int, value string) (a int, b string) {
	//转化成10进制,进行字符串拼接
	resultStr := strconv.FormatInt(int64(number), 10) + value
	return number, resultStr
}

// 多个入参、单个出参
func testFuntionV3(args ...int) (int, string, float64) { //(args ...int)表示可以传递多个参数,可以理解为0到多个参数
	resultNum := 0
	for arg := range args {
		fmt.Println("打印参数arg = ", arg)
		resultNum += arg
	}
	resultStr := "返回值2"
	resultFloatNum := 888.88
	fmt.Printf("最终返回值1=%v, 最终返回值2=%v, 最终返回值3=%v \n", resultNum, resultStr, resultFloatNum)
	return resultNum, resultStr, resultFloatNum
}

// init函数,最大的作用是用来初始化源文件,该函数会在main函数执行前被调用
func init() {
	//do something
	fmt.Println("初始化函数,先于main函数执行")
}

// ///匿名函数(全局变量)///
var (
	globalVariableFunc = func(number_1 int, number_2 int) (int, string) {
		return number_2 * number_1, strconv.FormatInt(int64(number_1), 10)
	}
)

// ///闭包///
// 含义:闭包是由函数和与其相关的引用环境组合而成的实体[抽象、难以理解!],其实就是:匿名函数+外部引用
// 为什么使用闭包(为了避免全局变量被滥用):可以让变量常驻内存、可以让变量不污染全局
// 可参考文章:https://blog.csdn.net/qq_27654007/article/details/116667624
func closureTest() func(int) int {
	var n int = 10
	return func(x int) int {
		//每一次调用都会给n进行累加赋值,n的值在内存中伴随整个闭包实例的整个生命周期
		n = n + x
		return n
	}
}

// ///defer///
func deferTest(strValue string) string {

	//依据打印输出可以看出来,defer这行的逻辑是在return那一刻执行的
	defer printString("defer 延迟执行测试")
	printString("deferTest 执行测试-1")
	printString("deferTest 执行测试-2")
	return strValue
}

func printString(str string) {
	fmt.Println(str)
}

// ///函数作为参数/
func testFuncArg(param func(str string)) {
	param("函数作为参数测试")
}

// ///函数作为返回值/
func testReturnFunc() func(result_1 int64, result_2 int64) int64 {
	return func(n1 int64, n2 int64) int64 {
		return n1 * n2
	}
}

运行结果

初始化函数,先于main函数执行
-------return测试---------
returnTest执行结果, result_1 = 8712, result_2 = 187 
returnTestV2执行结果, result_3 = 8712, result_4 = 187 
-------函数测试---------
funcResultV2_1 = 1, funcResultV2_2 = 1123 
最终返回值1=0, 最终返回值2=返回值2, 最终返回值3=888.88 
打印参数arg =  0
打印参数arg =  1
打印参数arg =  2
打印参数arg =  3
打印参数arg =  4
最终返回值1=10, 最终返回值2=返回值2, 最终返回值3=888.88 
-------匿名函数测试---------
anonymousFuncResult =  16
匿名函数赋值给变量之后n1 = 29, n2 = 10 
-------全局匿名函数测试---------
调用全局匿名函数结果globalVariableFuncResult_1 = 3 type: int, globalVariableFuncResult_1 = 1 type: string
闭包调用第1次返回结果:20 
闭包调用第2次返回结果:30 
闭包调用第3次返回结果:40 
新的闭包调用第1次返回结果:20 
-------defer测试---------
deferTest 执行测试-1
deferTest 执行测试-2
defer 延迟执行测试
-------函数作为参数测试---------
函数作为参数测试
-------函数作为返回值测试---------
函数作为返回值测试, 返回结果类型 = func(int64, int64) int64 
执行函数, 结果 = 20000, 类型 = int64 
-------内置函数测试---------
*p =  0 , p =  0x140000a6030
*p =  29

结构体

之前的变量只能定义一个使用一个,有时候可能需要很多个变量,当出现这种情况的时候我们可以使用struct结构体,
struct定义结构,结构由字段(field)组成,每个field都有所属数据类型,在一个struct中,每个字段名都必须唯一。

Go中不支持面向对象,面向对象中描述事物的类的重担由struct来挑。比如面向对象中的继承,可以使用组合(composite)来实现:struct中嵌套一个(或多个)类型。

结构如下

type UserInfo struct {
    field1 type1 
    field2 type2
    …
}

// 或者
type T struct { a, b int }

理论上,每个字段都是有具有唯一性的名字的,但如果确定某个字段不会被使用,可以将其名称定义为空标识符_来丢弃掉:

type T struct {
    _ string
    a int
}

示例代码

package main

import (
	"fmt"
)

type UserInfo struct {
	//用户姓名
	name string
	//年龄、身高
	age, height int16 //相同类型可以定义在一行
	//用户地址
	address string
}

// 如果里面的字段类型都一样可以使用这种方法
type UserInfoV2 struct{ name, address string }

// 组合型
type UserInfoV3 struct {
	user_1 UserInfo
	user_2 UserInfoV2
}

func main() {

	//初始化结构体
	info := UserInfo{age: 18, name: "小明", height: 180, address: "浙江省杭州市"}
	fmt.Printf("结构体信息:%v  \n", info)
	//访问结构体属性,info.xxx
	fmt.Printf("访问name信息:%v, age:%v, 访问height信息:%v, 访问address信息:%v   \n", info.name, info.age, info.height, info.address)
	//分配内存地址连续
	fmt.Printf("name分配内存地址:%v, age分配内存地址:%v, height分配内存地址:%v, address分配内存地址:%v   \n", &info.name, &info.age, &info.height, &info.address)
	//组合型结构体
	user_1 := UserInfo{age: 33, name: "Mir Zhang", height: 180, address: "北京"}
	user_2 := UserInfoV2{name: "Mir Li", address: "北京"}
	user_3 := UserInfoV3{user_1, user_2}
	fmt.Printf("结构体信息:%s  \n", user_3)

}

运行结果

初始化函数,先于main函数执行
结构体信息:{小明 18 180 浙江省杭州市}  
name:小明, age:18, height:180, address:浙江省杭州市   
name分配内存地址:0x14000112180, age分配内存地址:0x14000112190, height分配内存地址:0x14000112192, address分配内存地址:0x14000112198   
结构体信息:{{Mir Zhang %!s(int16=33) %!s(int16=180) 北京} {Mir Li 北京}}  

接口

interface类型可以定义一组方法,不需要实现。并且interface不能包含任何变量。

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
就是定义一个规范,让实现接口的实例按照这个规范来实现自己的逻辑

​ 以以下示例来讲,定义一个动物接口,里面有发出声音的接口,实现接口的动物实例按照各自的业务逻辑来实现这个发出声音的方法

代码示例

package main

import "fmt"

func main() {
	//根据不同的实例调用对应的实例方法
	doVoice(Dark{name: "小鸭子"})
	doVoice(new(Cat))

}

// 定义一个接口
type Animal interface { // type 接口名 interface
	voice()
}

// 定义结构体
type Dark struct {
	name string
}

type Cat struct {
	name string
}

// 实现接口方法
func (dark Dark) voice() { // 接口是引用类型,所以这里传递的是变量的引用
	fmt.Printf("%v 嘎嘎叫 \n", dark.name)
}

func (cat Cat) voice() { // 接口是引用类型,所以这里传递的是变量的引用
	fmt.Printf("喵喵叫 \n")
}

func doVoice(animal Animal) {
	animal.voice()
}

运行结果

小鸭子 嘎嘎叫 
喵喵叫 

继承

在java中继承相当于拥有父类的一些属性和方法
go里面继承可以通过嵌套匿名结构体来实现

代码示例

package main

import (
	"fmt"
)

func main() {
	father := Father{name: "父亲", phone: "13100001111"}
	fmt.Printf("父亲属性: %d \n", father)

	son := new(Son)
	son.hobby = "打篮球"
	son.name = "儿子"
	son.phone = "13033331111"
	fmt.Printf("儿子属性: %d \n", son)

}

type Father struct {
	name, phone string
}

type Son struct {
	Father //匿名结构体
	hobby  string
}

运行结果

父亲属性: {%!d(string=父亲) %!d(string=13100001111)} 
儿子属性: &{{%!d(string=儿子) %!d(string=13033331111)} %!d(string=打篮球)} 

type

type用于类型定义(type definition)与类型别名(type alias),可以理解就是定义一个类型或者给一个类型起别名

示例代码

package main

import (
	"fmt"
	"unsafe"
)

// 定义类型
type UserMsg struct {
	name, phone string
}

// 类型起别名
type myIntType int64

//结构体起别名
type MyUserMsg UserMsg

func main() {

	//使用起了别名的类型
	var number_test myIntType = 999
	fmt.Printf("number_test = %v, 类型:%T, 大小:%v字节  \n", number_test, number_test, unsafe.Sizeof(number_test))

	myUserMsg := MyUserMsg{name: "123", phone: "13111110000"}
	fmt.Printf("myUserMsg = %v, 类型:%T, 大小:%v字节  \n", myUserMsg, myUserMsg, unsafe.Sizeof(myUserMsg))

}

运行结果

number_test = 999, 类型:main.myIntType, 大小:8字节  
myUserMsg = {123 13111110000}, 类型:main.MyUserMsg, 大小:32字节  

值类型与引用类型

值类型:基本数据类型、数组、结构体。变量直接存储值,通常存储于栈中,函数传参时使用值传递

引用类型:指针、切片、映射、管道、接口等。变量存储的是值的地址,通常存储于堆中,会发生GC,函数传参时使用引用传递。

值传递、引用传递

值传递:使用按值传递来传递参数,也就是传递参数的副本。在函数中对副本的值进行更改操作时,不会影响到原来的变量。

引用传递:传递的是一个地址的拷贝,通过它可以修改这个值所指向的地址上的值。

在函数调用时,引用类型(slice、map、interface、channel)都默认使用引用传递,另外使用指针也可以进行引用传递。

package main

import (
	"fmt"
	"unsafe"
)

func main() {

	//值传递测试
	var number int64 = 999
	testV1(number)
	//从这里看出调用函数赋值后并不会改变原值
	fmt.Println("main()当前number=", number)

	//应用传递测试
	var i int = 10
	fmt.Printf("i当前的值 = %v \n", i)
	//1、ptr是一个指针变量 2、ptr存的是i变量的地址 3、类型是*int
	var ptr *int = &i
	//赋予新值
	*ptr = 20
	fmt.Printf("指针存储的值:%v, 类型:%T, 占内存字节数:%d, 指针存储地址指向的值:%d, 指针的地址:%v \n", ptr, ptr, unsafe.Sizeof(ptr), *ptr, &ptr)
	fmt.Printf("i修改后的值 = %v \n", i)
}

func testV1(number int64) {
	number = 1000
	fmt.Println("testV1()当前number=", number)
}

运行结果

testV1()当前number= 1000
main()当前number= 999
i当前的值 = 10 
指针存储的值:0x14000114018, 类型:*int, 占内存字节数:8, 指针存储地址指向的值:20, 指针的地址:0x14000100020 
i修改后的值 = 20 

打包、引用包

有时候我们除了引用go提供的官方包,也可能需要我们自己打包后在其他模块引用封装好的包

如我当前项目文件名为:MyTest
在项目文件路径下创建了packageUtils文件夹,在文件夹下创建了UtilsPKG.go文件

图示如下:

在这里插入图片描述

工具类打包文件代码

package packageUtils

func NumberUtils(number_1 int64, number_2 int64, operation string) (resultNumber float64) {

	switch operation {
	case "*":
		resultNumber = float64(number_2 * number_1)
		break
	case "/":
		resultNumber = float64(number_2 / number_1)
		break
	case "*+":
		resultNumber = float64(number_2 + number_1)
		break
	case "-":
		resultNumber = float64(number_2 - number_1)
		break
	}
	return
}

引用包代码

在其他路径下随意创建一个文件

package main

import (
	"MyTest/packageUtils"       //这块就是导入了我们上面打好的包
	"fmt"
)

func main() {
	resultNum := packageUtils.NumberUtils(100, 200, "*")
	fmt.Printf("执行包调用函数结果:%v", resultNum)
}

运行结果

包调用函数返回值: 200

方法

​ 方法虽不同于函数,是两个概念性的东西,但是方法和函数有些相似,如果之前没有接触过go方法和函数相关的知识,一定会犯迷糊,下面我们看看方法的用法,go中方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct。

go方法的声明(定义)

方法必须要有一个接收者(t type),这个接收者是一个类型,这样方法就和这个类型绑定在一起,称为这个类型的方法。

func (t type) methodName (参数列表) (返回值列表){
	方法体
	return 返回值
}

代码示例

package main

import (
	"fmt"
	"strconv"
	"unsafe"
)

func main() {
	var number_test MyInt = 888
	result_num := number_test.testMethod(999)
	println("testMethod invoke result:", result_num)

	personInfo := Person{Age: 20, Name: "Mr F"}
	result := personInfo.testMethodV2()
	fmt.Printf("testMethodV2 invoke result:%v, type:%T", result, result)

}

type MyInt int64

func (receiver MyInt) testMethod(number_1 int64) string {
	fmt.Println("this is a data type receiver,", receiver)
	return "-------" + strconv.FormatInt(number_1, 10) + "-------"
}

type Person struct {
	Name string
	Age  int
}

func (receiver Person) testMethodV2() Person {
	fmt.Println("this is a struct receiver,", receiver)
	return receiver
}

运行结果

this is a data type receiver, 888
testMethod invoke result: -------999-------
this is a struct receiver, {Mr F 20}
testMethodV2 invoke result:{Mr F 20}, type:main.Person

异常捕捉处理

go语言中没有像java中一样的try catch finally处理模块,

代码示例

package main

import (
	"fmt"
	"strconv"
	"strings"
	"unsafe"
)

func main() {
	
	//测试异常捕捉处理
	testExceptionCapture();
  
  fmt.Println("异常捕捉后继续处理流程")

	//测试异常panic
	testPanic();

	//上面函数执行报错后如果没有异常捕捉处理程序直接结束运行
	fmt.Println("异常捕捉处理测试")
}

func testPanic() {
	n1 := 1
	n2 := 0
	n3 := n1 / n2

	//发送异常之后,下面的输出语句不会输出,程序直接结束
	fmt.Println("res:", n3)
}

func testExceptionCapture() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("捕获到的异常信息: ", err)
			//异常之后做一些事情
			fmt.Println("发送钉钉告警或者邮件告警等")
		}
	}()

	n1 := 1
	n2 := 0
	n3 := n1 / n2

	//发送异常之后,下面的输出语句不会输出
	fmt.Println("res:", n3)
}

运行结果

捕获到的异常信息:  runtime error: integer divide by zero
发送钉钉告警或者邮件告警等
异常捕捉后继续处理流程
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.testPanic()
        /Users/dasouche/go/src/MyTest/TwoTest.go:27 +0x1c
main.main()
        /Users/dasouche/go/src/MyTest/TwoTest.go:18 +0x64

字符串常用函数

参考中文文档strings包相关:https://studygolang.com/static/pkgdoc/pkg/strings.htm

代码示例

package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

func main() {

		//统计字符串的长度,按字节 len(str)
	var str string = "hello word"
	fmt.Printf("str长度:%v \n", len(str))
	//字符串遍历,同时处理有中文的问题 r := []rune(str)
	r := []rune(str)
	for i := range r {
		fmt.Printf("遍历字符串:%v \n", i)
	}
	//字符串转整数: n , err := strconv.Atoi(“12”)
	number_1, _ := strconv.Atoi("12")
	number_2, err_2 := strconv.Atoi("test")
	fmt.Printf("字符串转整数,number_1:%v \n", number_1)
	fmt.Printf("字符串转整数,number_2:%v, 错误信息:%v \n", number_2, err_2)

	//整数转字符串: str = strconv.Itoa(12345)、strconv.FormatInt(999, 10)
	str = strconv.Itoa(12345)
	fmt.Printf("整数转字符串,str:%v \n", str)
	str = strconv.FormatInt(999, 10)
	fmt.Printf("整数转字符串,str:%v \n", str)
	//字符串转[]byte: var bytes= []byte(“hello go”)
	var bytes = []byte("hello word")
	fmt.Printf("字符串转byte数组,str:%v \n", bytes)
	//[]byte转字符串: str = string([]byte{97,98,99})
	str = string([]byte{97, 98, 99})
	fmt.Printf("byte转字符串,str:%v \n", str)
	//10进制转2,8,16进制: str = strconv.FormatInt(123,2) // 2->8,16S
	str = strconv.FormatInt(123, 2)
	fmt.Printf("数字转2进制字符串,str:%v \n", str)
	str = strconv.FormatInt(123, 8)
	fmt.Printf("数字转8进制字符串,str:%v \n", str)
	str = strconv.FormatInt(123, 10)
	fmt.Printf("数字转10进制字符串,str:%v \n", str)
	str = strconv.FormatInt(123, 16)
	fmt.Printf("数字转16进制字符串,str:%v \n", str)

	//查找子串是否在指定的字符串中: strings.Contains(“seafood”, “foo”) //true
	isContains := strings.Contains("food foo eat", "foo")
	fmt.Printf("是否包含字符串foo,isContains:%v \n", isContains)

	//统计一个字符串有几个指定的子串:strings.Count(“ceheese”, “e”) //4
	countNum := strings.Count("hello word", "l")
	fmt.Printf("字符串含有%d个l:%v \n", countNum)

	//不区分大小写的字符串比较(== 是区分字母大小写的): fmt.PrintIn(strings.EqualFold(“abc”, “Abc”) // true
	isEqual := strings.EqualFold("abc", "Abc")
	fmt.Printf("字符串不区分大小写比较是否相等:%v \n", isEqual)
	fmt.Printf("字符串区分大小写比较是否相等:%v \n", "abc" == "Abc")

	//返回子串在字符串第一次出现的index值,如果没有返回-1 : strings.Index(“NLT_abc”,”abc”) //4
	firstIndex := strings.Index("hello word hello word", "ll")
	fmt.Printf("字符子串在字符串中第一次出现的地方:%v \n", firstIndex)

	//返回子串在字符串最后一次出现的index,如没有返回-1 : strings.LastIndex(“go golang” , “go”)
	lastIndex := strings.LastIndex("hello word hello word", "ll")
	fmt.Printf("字符子串在字符串中最后一次出现的地方:%v \n", lastIndex)

	//将指定的子串替换成 另外一个子串: strings.Replace(“go go hello” , “go”, “go语言”, n) n 可以指定你希望替换几个,如果n = -1表示全部替换
	str = strings.Replace("hello word hello word", "ll", "ll-", 2)
	fmt.Printf("替换后的字符串:%v \n", str)

	//按照指定的某个字符,为分割标识,将一个字符串拆分成字符串数组:
	splitData := strings.Split("Mr Li,20,北京朝阳区", ",")
	fmt.Printf("分割后的数据:%v \n", splitData)

	//将字符串的字母进行大小写的转换: strings.ToLower(“Go”) // go strings.ToUpper(“Go”) //GO
	str = strings.ToLower("HELLO Word")
	fmt.Printf("转换成小写后的数据:%v \n", str)
	str = strings.ToUpper("hello Word")
	fmt.Printf("转换成大写后的数据:%v \n", str)

	//将字符串左右两边的空格去掉 : strings.TrimSpace(“ tn a lone gopher ntrn “)
	str = strings.TrimSpace(" hello, word ")
	fmt.Printf("去掉空格后的数据:%v \n", str)

	//将字符串左右两边指定的字符去掉: strings.Trim(“! hello! “, “ !”) // [“hello”]//将左右两边!和””去掉
	str = strings.Trim("! hello, word !", "!")
	fmt.Printf("去掉!后的数据:%v \n", str)

	//将字符串左边指定的字符去掉: strings.TrimLeft(“! hello! “,” !”) // [“hello”]//将左边!和”“去掉
	str = strings.TrimLeft("! hello, word !", "!")
	fmt.Printf("去掉左边!后的数据:%v \n", str)

	//将字符串右边指定的字符去掉: strings.TrimRight(“! hello! “,” !”) // [“hello”]//将右边!和””去掉
	str = strings.TrimRight("! hello, word !", "!")
	fmt.Printf("去掉右边!后的数据:%v \n", str)

	//判断字符串是否以指定的字符串开头: strings.HasPrefix(“ftp://192.168.10.1" ,”ftp”) // true
	hasPrefix := strings.HasPrefix("! hello, word !", "!")
	fmt.Printf("是否以!开头:%v \n", hasPrefix)

	//判断字符串是否以指定的字符串结束: strings.HasSuffix(“‘NLT_abc.jpg”,”abc”) //false
	hasSuffix := strings.HasSuffix("! hello, word !", "!")
	fmt.Printf("是否以!结束:%v \n", hasSuffix)

	//判断字符串是否包含一个字符串
	hasContains := strings.Contains("hello word", "hello")
	fmt.Printf("字符串hello word是否包含hello:%v \n", hasContains)

}



运行结果

str长度:10 
遍历字符串:0 
遍历字符串:1 
遍历字符串:2 
遍历字符串:3 
遍历字符串:4 
遍历字符串:5 
遍历字符串:6 
遍历字符串:7 
遍历字符串:8 
遍历字符串:9 
字符串转整数,number_1:12 
字符串转整数,number_2:0, 错误信息:strconv.Atoi: parsing "test": invalid syntax 
整数转字符串,str:12345 
整数转字符串,str:999 
字符串转byte数组,str:[104 101 108 108 111 32 119 111 114 100] 
byte转字符串,str:abc 
数字转2进制字符串,str:1111011 
数字转8进制字符串,str:173 
数字转10进制字符串,str:123 
数字转16进制字符串,str:7b 
是否包含字符串foo,isContains:true 
字符串含有2个l:%!v(MISSING) 
字符串不区分大小写比较是否相等:true 
字符串区分大小写比较是否相等:false 
字符子串在字符串中第一次出现的地方:2 
字符子串在字符串中最后一次出现的地方:13 
替换后的字符串:hell-o word hell-o word 
分割后的数据:[Mr Li 20 北京朝阳区] 
转换成小写后的数据:hello word 
转换成大写后的数据:HELLO WORD 
去掉空格后的数据:hello, word 
去掉!后的数据: hello, word  
去掉左边!后的数据: hello, word ! 
去掉右边!后的数据:! hello, word  
是否以!开头:true 
是否以!结束:true 
字符串hello word是否包含hello:true 

日期常用函数

参考中文文档time包相关:https://studygolang.com/static/pkgdoc/pkg/time.htm

代码示例

package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

func main() {

	println("-----常用日期函数测试----")
	//返回当前系统时间
	currentTime := time.Now()
	fmt.Printf("当前系统时间=%v \n", currentTime)
	//返回当前系统时间年、月、日、日、时、分、秒、毫秒
	date, month, day := currentTime.Date()
	fmt.Printf("当前系统年=%v,月=%v,日=%v \n", date, month, day)
	currentTimeYear := currentTime.Year()
	currentTimeDay := currentTime.Day()
	currentTimeMonth := currentTime.Month()
	currentTimeHour := currentTime.Hour()
	currentTimeMinute := currentTime.Minute()
	currentTimeSecond := currentTime.Second()
	//时间戳
	currentTimeUnixMilli := currentTime.UnixMilli()
	//纳秒:常用于生成随机数字(如生成订单号、随机序列等)
	currentTimeUnixNano := currentTime.UnixNano()
	//方法【Unix】将t表示为Unix时间,即从时间点January 1, 1970 UTC到时间点t所经过的时间(单位秒)
	currentTimeUnix := currentTime.Unix()
	fmt.Printf("当前系统年=%v,月=%v,日=%v,时=%v,分=%v,秒=%v,当前系统毫秒数=%v,当前系统纳秒数=%v,Unix时间=%v  \n", currentTimeYear, currentTimeDay, currentTimeMonth,
		currentTimeHour, currentTimeMinute, currentTimeSecond, currentTimeUnixMilli, currentTimeUnixNano, currentTimeUnix)

	//Duration 类型用于表示两个时刻 ( Time ) 之间经过的时间,以 纳秒 ( ns ) 为单位。 点击进去可以看到是time里面的自定义类型:type Duration int64
	start_time := time.Now()
	// 空循环 uint32 的最大值次数
	const UINT32_MAX uint32 = ^uint32(0)
	var i uint32
	for i = 0; i < UINT32_MAX; i += 1 {

	}
	end_time := time.Now()
	spand_time := time.Duration(end_time.Sub(start_time))
	fmt.Printf("空循环 uint32 的最大值次数耗时时间(s):%v \n", spand_time.Seconds())

	println("------时间格式化-----")
	var now = time.Now()
	// 以下的数字都是固定的值,不能更换,据说2006/01/02 15:04:05是创始人思考创建go的时间
	fmt.Println(now.Format("2006")) // 2022
	fmt.Println(now.Format("01"))   // 04
	fmt.Println(now.Format("02"))   // 30
	fmt.Println(now.Format("15"))   // 10
	fmt.Println(now.Format("04"))   // 52
	fmt.Println(now.Format("05"))   // 16

	// 数字之外的其它字符可以更换
	fmt.Println(now.Format("2006/01/02 15:04:05")) // 2022/04/30 10:52:16
	fmt.Println(now.Format("2006-01-02 15:04:05")) // 2022-04-30 10:52:16

	println("------sleep练习-----")
	sleep_start_time := time.Now()
	var num = 1
	for {
		fmt.Printf("%v ", num)
		//休眠30ms
		time.Sleep(time.Millisecond * 30)
		if num == 5 {
			println()
			break
		}
		num++
	}
	sleep_end_time := time.Now()
	sleep_spand_time := sleep_end_time.Sub(sleep_start_time)
	fmt.Printf("sleep 测试耗费时间(ms):%v \n", sleep_spand_time.Milliseconds())

	println("------时间戳 <-互转-> 日期字符串-----")
	// 时间戳转换年月日时分秒(一个参数是秒,另一个参数是纳秒)
	//Unix返回与给定Unix时间相对应的本地时间,
	//秒和纳秒。
	var time_1 = time.Unix(1595289901, 0)
	var timeStr = time_1.Format("2006-01-02 15:04:05")
	fmt.Println("时间戳转时间字符串结果:%v \n", timeStr)

	// 日期字符串转换成时间戳
	var timeStr2 = "2022-11-25 14:44:52"
	var tmp = "2006-01-02 15:04:05" //转换模版
	timeObj5, _ := time.ParseInLocation(tmp, timeStr2, time.Local)
	fmt.Println("日期字符串转换成ms时间戳结果:%v \n", timeObj5)

}

运行结果

-----常用日期函数测试----
当前系统时间=2022-11-25 14:45:58.212786 +0800 CST m=+0.000256501 
当前系统年=2022,=November,=25 
当前系统年=2022,=25,=November,=14,=45,=58,当前系统毫秒数=1669358758212,当前系统纳秒数=1669358758212786000,Unix时间=1669358758  
空循环 uint32 的最大值次数耗时时间(s):1.362262833 
------时间格式化-----
2022
11
25
14
45
59
2022/11/25 14:45:59
2022-11-25 14:45:59
------sleep练习-----
1 2 3 4 5 
sleep 测试耗费时间(ms):154 
------时间戳 <-互转-> 日期字符串-----
时间戳转时间字符串结果:%v 
 2020-07-21 08:05:01
日期字符串转换成ms时间戳结果:%v 
 2022-11-25 14:44:52 +0800 CST

管道(channel)

管道(channel)为引用类型,必须先初始化才能使用;本质是一个队列,有类型,而且线程安全.
管道的定义: var 变量名 chan 数据类型

代码示例

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	println("------管道测试-------")
	//简单用法
	simpleChannel := make(chan int, 2)
	simpleChannel <- 100
	simpleChannel <- 200

	//取出管道数据丢弃
	<-simpleChannel
	channelInfo := <-simpleChannel
	fmt.Printf("读取simpleChannel管道数据: %v \n", channelInfo)

	intsChannel := make(chan int, 50)
	//协程相关在后续进阶篇中介绍,相当于开启一个新的线程执行逻辑,不阻塞main()线程的逻辑执行
	//开启协程,用于写数据
	go func() {
		for true {
			writeNum := rand.Intn(100)
			intsChannel <- writeNum
			fmt.Printf("写入管道数据: %v \n", writeNum)
			time.Sleep(time.Millisecond * 500)
		}
	}()

	//开启协程,用于读数据
	go func() {
		for true {
			//读取管道数据
			readInfo := <-intsChannel
			fmt.Printf("读取管道数据: %v \n", readInfo)
			time.Sleep(time.Millisecond * 500)
		}
	}()

	//防止数据还没有在协程里打印,main函数退出,main()执行结束后其他相关的协程也会结束
	time.Sleep(time.Second * 3)

	//程序结束
}

运行结果

------管道测试-------
读取simpleChannel管道数据: 200 
写入管道数据: 81 
读取管道数据: 81 
写入管道数据: 87 
读取管道数据: 87 
写入管道数据: 47 
读取管道数据: 47 
写入管道数据: 59 
读取管道数据: 59 
写入管道数据: 81 
读取管道数据: 81 
写入管道数据: 18 
读取管道数据: 18 
学海无涯,吾生也有涯,而知也无涯,以有涯随无涯. 加油👍

后续还会加入进阶篇,有兴趣的点个关注吧

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

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

相关文章

RDD—Transformation算子

Spark核心编程&#xff08;Spark Core&#xff09; 文章目录Spark核心编程&#xff08;Spark Core&#xff09;1. 了解RDD1.2 RDD五大特性1.3 WordCount案例分析2 RDD编程入门2.1 RDD的创建2.2 RDD算子2.3 常用Transformation 算子小案例&#xff08;客户端&#xff0c;集群&am…

Flutter高仿微信-第45篇-群聊-文本

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; 详情请参考Flutter高仿微信-第44篇-群聊&#xff0c; 这里…

Win10更新后卡在输入密码的界面

注意&#xff1a; 系统没问题时候建议创建还原点&#xff0c;以防万一&#xff1a; 创建还原点方法&#xff1a; 设置-系统-关于-系统保护-创建还原点。 下面介绍Win10更新后卡在输入密码的界面解决方法。 此时进不去系统&#xff0c;想进行还原点还原。 首先需要进入疑难解答…

安全分析能力的核心能力

核心能力 为了加快安全分析能力更全面、更深入的自动化 &#xff0c;SecXOps 的目标在于创建一个集成的用于 Security 的 XOps 实践&#xff0c;提升安全分析的场景覆盖率和运营效率。SecXOps 技术并不 015 SecXOps 技术体系 是 Ops 技术在安全领域的简单加和&#xff0c;SecXO…

第二章:线程基础知识复习

为什么要学好多线程如此重要? 硬件方面 摩尔定律 它是由英特尔创始人之一-Gordon Moore(戈登●摩尔)提出来的。其内容为: . 当价格不变时&#xff0c;集成电路上可容纳的元器件的数目约每隔18-24个月便会增加一倍&#xff0c;性能也将提升一倍。换言之&#xff0c;每一美元所…

力扣 36. 有效的数独 C语言实现

题目描述&#xff1a; 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参…

嵌入式驱动初级-阻塞与非阻塞

文章目录前言一、五种IO模型二、阻塞与非阻塞三、多路复用四、信号驱动前言 记录嵌入式驱动学习笔记 一、五种IO模型 当应用程序对设备驱动进行操作的时候&#xff0c;如果不能获取到设备资源&#xff0c;那么阻塞式 IO 就会将应用程 序对应的线程挂起&#xff0c;直到设备资源…

LeetCode刷题复盘笔记—一文搞懂纯0-1背包问题(动态规划系列第六篇)

今日主要总结一下动态规划背包问题的基础——纯0-1背包问题 在Leetcode题库中主要都是01背包和完全背包的应用问题&#xff0c;所以主要掌握这两个背包问题 题目&#xff1a;纯0-1背包问题 题目描述&#xff1a; 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是wei…

推特自动发帖,全天占据核心流量

利用热门趋势和Hashtags标签 Twitter有一个热门趋势&#xff0c;跟微博热搜是差不多的&#xff0c;卖家可以多关注一下热门趋势&#xff0c;看看有没有和产品相关的内容。在帖子中加入趋势性和热门的标签&#xff0c;是一种非常好的营销方式。 这一方面能够增加推文的热度&am…

【Linux】(五)GateWay远程开发方式-实验室服务器使用GateWay远程开发

Jetbrains GateWay 方式系列文章一、服务器情况简介1.1服务器及用户1.2 cuda1.3 conda环境二、Jetbrains GateWay方式连接2.1 下载2.2 配置2.3 连接管理及附加说明2.3.1 关闭或退出2.3.2 重连附录公共数据集系列文章 &#xff08;一&#xff09;服务器初次配置及安装vncserver…

基于MxNet实现目标检测-YoloV4【附部分源码及模型】

文章目录前言目标检测发展史及意义一、数据集的准备1.标注工具的安装2.数据集的准备3.标注数据4.解释xml文件的内容二、网络结构的介绍三、代码实现0.工程目录结构如下1.导入库2.配置GPU/CPU环境3.数据加载器4.模型构建5.模型训练1.学习率设置2.优化器设置3.损失设置4.循环训练…

Hive基本使用

Hive系列第三章 第三章 基本使用 1、 创建库&#xff1a;create database mydb; 2、 查看库&#xff1a;show databases; 3、 切换数据库&#xff1a;use mydb; 3.1 访问Hive的方式 3.1.1 直接可以在客户端Hive进入 见2.5.8 启动hive客户端 3.1.2 使用JDBC方式 先知道&am…

汽车零部件加工行业工业互联网智能工厂解决方案

汽车零部件分类 汽车零部件是汽车工业发展的基础。按功能分类如下&#xff1a; 零部件分类 主要产品 发动系统 发动机总成、滤清器、气缸及部件、油箱、曲轴、凸轮轴、气门及部件、皮带、增压器、化油器、燃油喷射装置、其他发动系统 传动系统 离合器、减速器总成、变速器…

【C++ STL】-- 二叉搜索树

目录 二叉搜索树概念 二叉搜索树的应用 二叉搜索树的实现&#xff08;K模型&#xff09; 构造函数 默认拷贝构造函数 赋值运算符重载函数 普通写法&#xff1a; 进阶写法&#xff1a; 析构函数 插入函数&#xff08;Insert&#xff09;的实现 常规实现&#xff1a; …

解决Windows环境下的docker中修改了mysql的配置文件之后启动不了的问题

** 前情简介&#xff1a; ** 由于在docker中安装的mysql5.7中区分表的大小写&#xff0c;进入到mysql的命令行模式之后就修改配置文件&#xff0c;主要修改 lower_case_table_names1修改之后就启动再也启动不起来了&#xff0c;说我配置文件改错了 2022-11-25 14:47:5400:0…

ThingsBoard源码解析-消息队列

概述 消息队列是thingsboard支持集群的基础&#xff0c;比如使用Kafka可实现消息在整个服务集群中共同处理&#xff0c;提高性能。如果是内存队列&#xff0c;则无法再服务实例间共享消息。 定义 在module【common/cluster-api】的org.thingsboard.server.queue包定义了消息…

排名预测系统

排名预测系统 题目链接 题目背景&#xff1a; 本题大模拟来自真实的需求&#xff0c;即&#xff1a;综合三场网络赛的名次&#xff0c;来预计一个正式队伍在所有正式参赛队伍中的名次以此来估计自己能不能拿牌。本来只有一道题&#xff0c;即为你们看到的T5&#xff0c;经过…

【Linux kernel/cpufreq】framework ----big Little driver

Linux kernel支持ARM bigLttile框架的解决方案 一般ARM SOC包含能效和性能两个cluster&#xff0c;共8个 core&#xff0c;可以把这8个core统统开放给kernel&#xff0c;让kernel的调度器&#xff08;scheduler&#xff09;根据系统的实际情况&#xff0c;决定哪些任务应该在哪…

C++ 值传递、引用传递、指针传递

一、简介 参数传递的三种方式&#xff1a;值传递、引用传递、指针传递 二、举例如下 #if 1 值传递 引用传递 指针传递的区别void value_input(int a){cout << "值传递------函数" <<&a <<endl;a 100;}void Pointer_input(int * n){cou…

云上办公兴起,华为云桌面Workspace更靠谱

云上办公兴起&#xff0c;华为云桌面Workspace更靠谱 为了办公的便利性&#xff0c;也趁着华为云推行“实惠更实用&#xff0c;11都如愿”的主题活动&#xff0c;许多企业果断入手了华为云桌面Workspace服务&#xff0c;当亲自试用后&#xff0c;才逐渐感受使用华为云桌面Work…