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

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

文章目录


函数进阶

结构体

接口

继承

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文件

图示如下:

1.png

工具类打包文件代码

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)
}


管道(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 

学海无涯,吾生也有涯,而知也无涯,以有涯随无涯. 加油👍

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

相关文章
|
8天前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
36 0
|
1天前
|
存储 编译器 Go
Go语言学习12-数据的使用
【5月更文挑战第5天】本篇 Huazie 向大家介绍 Go 语言数据的使用,包含赋值语句、常量与变量、可比性与有序性
18 6
Go语言学习12-数据的使用
|
2天前
|
Java Go
一文带你速通go语言指针
Go语言指针入门指南:简述指针用于提升效率,通过地址操作变量。文章作者sharkChili是Java/CSDN专家,维护Java Guide项目。文中介绍指针声明、取值,展示如何通过指针修改变量值及在函数中的应用。通过实例解析如何使用指针优化函数,以实现对原变量的直接修改。作者还邀请读者加入交流群深入探讨,并鼓励关注其公众号“写代码的SharkChili”。
9 0
|
2天前
|
存储 缓存 Java
来聊聊go语言的hashMap
本文介绍了Go语言中的`map`与Java的不同设计思想。作者`sharkChili`是一名Java和Go开发者,同时也是CSDN博客专家及JavaGuide项目的维护者。文章探讨了Go语言`map`的数据结构,包括`count`、`buckets指针`和`bmap`,解释了键值对的存储方式,如何利用内存对齐优化空间使用,并展示了`map`的初始化、插入键值对以及查找数据的源码过程。此外,作者还分享了如何通过汇编查看`map`操作,并鼓励读者深入研究Go的哈希冲突解决和源码。最后,作者提供了一个交流群,供读者讨论相关话题。
10 0
|
3天前
|
Java Go
Go语言学习11-数据初始化
【5月更文挑战第3天】本篇带大家通过内建函数 new 和 make 了解Go语言的数据初始化过程
17 1
Go语言学习11-数据初始化
|
3天前
|
自然语言处理 安全 Java
速通Go语言编译过程
Go语言编译过程详解:从词法分析(生成token)到句法分析(构建语法树),再到语义分析(类型检查、推断、匹配及函数内联)、生成中间码(SSA)和汇编码。最后,通过链接生成可执行文件。作者sharkchili,CSDN Java博客专家,分享技术细节,邀请读者加入交流群。
22 2
|
4天前
|
Java Linux Go
一文带你速通Go语言基础语法
本文是关于Go语言的入门介绍,作者因其简洁高效的特性对Go语言情有独钟。文章首先概述了Go语言的优势,包括快速上手、并发编程简单、设计简洁且功能强大,以及丰富的标准库。接着,文章通过示例展示了如何编写和运行Go代码,包括声明包、导入包和输出语句。此外,还介绍了Go的语法基础,如变量类型(数字、字符串、布尔和复数)、变量赋值、类型转换和默认值。文章还涉及条件分支(if和switch)和循环结构(for)。最后,简要提到了Go函数的定义和多返回值特性,以及一些常见的Go命令。作者计划在后续文章中进一步探讨Go语言的其他方面。
10 0
|
5天前
|
JavaScript 前端开发 Go
Go语言的入门学习
【4月更文挑战第7天】Go语言,通常称为Golang,是由Google设计并开发的一种编程语言,它于2009年公开发布。Go的设计团队主要包括Robert Griesemer、Rob Pike和Ken Thompson,这三位都是计算机科学和软件工程领域的杰出人物。
13 1
|
5天前
|
Go
|
6天前
|
分布式计算 Java Go
Golang深入浅出之-Go语言中的分布式计算框架Apache Beam
【5月更文挑战第6天】Apache Beam是一个统一的编程模型,适用于批处理和流处理,主要支持Java和Python,但也提供实验性的Go SDK。Go SDK的基本概念包括`PTransform`、`PCollection`和`Pipeline`。在使用中,需注意类型转换、窗口和触发器配置、资源管理和错误处理。尽管Go SDK文档有限,生态系统尚不成熟,且性能可能不高,但它仍为分布式计算提供了可移植的解决方案。通过理解和掌握Beam模型,开发者能编写高效的数据处理程序。
134 1