当前位置: 首页 > news >正文

go基础语法练习

go基础

字符串

1.字符串var str string = ``(使用反引号可以实现字符串中出现双引号也不用转义字符“\”进行转义)

2,将其他数据类型转为字符串

两种方式:

//方法一
var by byte = 'a'
var strs = fmt.Sprintf("%c", by)
fmt.Printf("%T", strs)
fmt.Println()
//方法二
var boo bool = true
formatBool := strconv.FormatBool(boo)
fmt.Printf("%q", formatBool)

基本的格式化动词

格式化动词说明示例代码输出示例
%v默认格式的值fmt.Printf("%v", 42)42
%+v打印结构体时包含字段名(更详细)fmt.Printf("%+v", person){Name:Alice Age:20}(带字段名)
%#vGo 语法表示的值(包括类型)fmt.Printf("%#v", 42)42 fmt.Printf("%#v", "hi")"hi" fmt.Printf("%#v", struct{Name string}{"Tom"})struct { Name string }{Name: "Tom"}
%T打印值的类型fmt.Printf("%T", 42)int
%t布尔值(true/false)fmt.Printf("%t", true)true

标识符和运算符:

变量名尽量使用驼峰命名法

一个go文件用的包是尽量用package main,可以在每次新建一个包下再建一个main包,实现go文件中包名与父包名相同

go语言与Java语言中“++”操作不能混淆,Java中++可以放在变量前也可以放在变量后面,但是在go语言中++就是简单的变量自增加一,并且只能放在变量的后面,不能放在变量的前面

switch分支注意事项:

注意事项:

case后面可以跟多个值 比如case:var1,var2,var3

case后面的常量值的数据类型要和switch后面的数据类型一致

case后面的的常量值不能重复,否则会报错

case后面不用跟break(与Java做区分,Java中case后面需要跟break)

default不是必须的,可有可无

switch后面不用非要跟表达式,可以当“if”使用,可以在case后面跟表达式

switch后面可以声明变量以分号结束,不推荐

switch b := 10; {
case b > 9:fmt.Println("....")
case b > 12:fmt.Println("///////")
}

switch穿透(fullthrough关键字)可以执行多个case分支(Java中不能实现switch的穿透,只能执行一个case分支)

for循环:

使用for循环遍历字符串的两种方式:

var name = "sncjdnghdmdfkg"
//方式一
for i := 0; i < len(name); i++ {fmt.Printf("%c", name[i])fmt.Println()
}//方式二
for i, j := range name {fmt.Printf("索引是%v,直是%c", i, j)fmt.Println()
}

循环终止关键字:break

break + 标签 可以实现指定终止那一层循环

continue加标签也可以实现

goto + 标签可以无条件跳转到程序的指定行

//使用一个标签用于指定终止那一层循环
label1:for i := 0; i < 3; i++ {for j := 0; j < 3; j++ {if i == 4 && j == 5 {break label1}fmt.Println(i, "==========", j)}}
}

函数:

函数的特点:

不支持方法重载

方法的参数,是将原参数复制一份,传参,简而言之就是方法体参数与原始数据的地址不一致

基本数据类型和数组默认都是值传递,即进行值拷贝,在函数内修改,不会影响原来的值

golang中支持传递可变参数

go中函数可看作数据类型 案例如下:

//函数也可以作为一个特殊的数据类型func test(num int) {fmt.Println(num)
}func main() {a := testa(10)var num = 20test2(num, a)
}
//给func(int)这一数据类型起别名
type myFunc func(int)func test2(num int, a myFunc) {a(num)
}

go函数中支持对返回值命名!!

可以给包进行起别名 如下:

import (//将报名起个aaa的别名aaa "Test/8funcType/utils""fmt"
)//函数也可以作为一个特殊的数据类型func test(num int) {fmt.Println(num)
}func main() {a := testa(10)var num = 20test2(num, a)//起完别名后,就只能用别名来调用包中的方法了aaa.ExchangeNum3(10, 20, 30, 40)
}type myFunc func(int)func test2(num int, a myFunc) {a(num)
}

值传递的两种方法:

func main() {var numa int = 10var numb int = 20fmt.Println(numa, numb)numa, numb = exchangeNum(numa, numb)fmt.Println(numa, numb)fmt.Println("值交换第二种方法==============================")exchangeNum2(&numa, &numb)fmt.Println(numa, numb)
}// 传地址
func exchangeNum2(a *int, b *int) {var temp inttemp = *a*a = *b*b = temp
}// 传数值
func exchangeNum(numa int, numb int) (int, int) {var temp inttemp = numanuma = numbnumb = tempreturn numa, numb
}

自定义类型和类型别名:

//自定义数据类型type Code0 int
type Code1 = intconst (SuccessCode1     Code0 = 1SuccessAliasCode Code1 = 2
)func main() {fmt.Printf("%v,%T\n", SuccessCode1, SuccessCode1)fmt.Printf("%v,%T\n", SuccessAliasCode, SuccessAliasCode)
}

差异:

1,类型别名无法绑定方法 自定义类型可以

2,类型别名的打印出来的类型还是原始类型

3,类型别名与原始数据类型进行比较时,类型别名不用转换直接可以比较

init函数:

初始化函数,可以用来进行一些初始话操作,每个源文件都可以包含一个init函数,该函数会在main函数执行前,被GO运行框架调用

匿名函数:

匿名函数不用定义函数名

// 匿名函数
func main() {//这里func后面只有参数类型result := func(a int, b int) int {return a + b}(10, 20)fmt.Println(result)sum := func(a int, b int) int {return a + b}result2 := sum(10, 20)fmt.Println(result2)result3 := sum(30, 40)fmt.Println(result3)
}

函数闭包:

注意:num会一直存在于匿名函数中

匿名函数中引用的那个变量会一直保存在内存中,可以一直使用

闭包的本质:

闭包本质依旧是一个匿名函数,只是这个函数引入外界的变量/参数

匿名函数+引用的变量/参数 = 闭包

func aaa() func(int) int {var num = 10return func(i int) int {num = num + ireturn num}
}
// 匿名函数
func main() {//函数闭包f := aaa()fmt.Println(f(1))//第一次的值是11fmt.Println(f(1))//第二次调用函数输出值是12
}

不应用闭包的时候,我想保留的值,不可以反复使用

闭包应用场景:闭包可以保留上次引用的某个值,我们传入一次就可以反复使用了

特点:

1.返回的是一个匿名函数,但是这个匿名函数引用到函数外的变量/参数,因此这个匿名函数就和变量/参数形成一个整体,构成闭包

2.闭包中使用的变量/参数会一直保存在内存中,所以会一直使用,意味着闭包不可滥用

defer关键字:

**栈的特点:**先进后出

在go中程序遇到defer关键字,不会立即执行defer的语句,而是将defer后的语句压入一个栈中,然后继续执行

在函数执行完毕后,从栈中取出语句开始执行,按照先进后出的规则执行语句

func add(num1 int, num2 int) int {//将num1 的值先拷贝一份,压入栈中,再将num2中的值拷贝一份压入栈中,最后输出时先输出num2 在输出num1defer fmt.Println(num1) defer fmt.Println(num2)fmt.Println(num1 + num2)return num1 + num2
}// defer 关键字
func main() {fmt.Println(add(10, 20))
}

注意:

遇到defer关键字,会将后面的代码语句压入栈中,也会将相关的值同时拷贝入栈中,不会随着函数后面的变化而变化

系统函数:

字符串函数:

对于字符串普通符号占一个字节,汉字一个字占3个字节

方法一二再for循环中找

方法三:

[]rune(str)

字符串转为切片并遍历

var str string = "xhanfhjamngkamd魏正想"// 常见的系统函数
func main() {strs := []rune(str)for i := 0; i < len(strs); i++ {fmt.Printf("%c\n", strs[i])}
}

字符串转数字:

strconv.Atoi(nnn)

var nnn string = "234"
//方法一
result, _ := strconv.ParseInt(nnn, 10, 16)
fmt.Println(result)
//方法二
result1, _ := strconv.Atoi(nnn)
fmt.Println(result1)

数字转字符串:

strconv.Itoa(123)

result2 := strconv.Itoa(123)
fmt.Printf("%T\n", result2)
fmt.Println(result2)

判断某个子串是否在字符串中:

strings.Contains(“golang”, “go”)

//判断go是否在golang字符串中
flag := strings.Contains("golang", "go")
fmt.Println(flag)

判断某个子串在字符串中出现的次数:

strings.Count(“gogogogogogogogo”, “go”)

//判断字符串中有多少个指定字符
counts := strings.Count("gogogogogogogogo", "go")
fmt.Println(counts)

不区分大小写比较字符串

//不区分大小写比较字符串
flag1 := strings.EqualFold("golang", "GOLANG")
fmt.Println(flag1)

找到字符串中给定子串第一次出现的索引值

//找到字符串中给定子串第一次出现的索引值
index := strings.Index("sndjdngjcuengicneng", "qi")
fmt.Println(index)

字符串的替换:

//字符串的替换
//参数分析,1,原字符串 2,被替换的子串 3,新的子串 4,替换几个老子串
result3 := strings.Replace("goadnjavagogo", "go", "golang", 2)
fmt.Println("字符串的替换")
fmt.Println(result3)

字符串其他操作:

//字符串的分割
result4 := strings.SplitAfter("gog-ogog-ogogogsuejf-idmg", "-")
fmt.Printf("字符串分割后的数据类型%T", result4)
fmt.Println()
fmt.Println(result4)//字符串大小写字母转换
upper := strings.ToUpper("lulu")
fmt.Println(upper)
lower := strings.ToLower("LULU")
fmt.Println(lower)//去掉字符串两边空格
space := strings.TrimSpace("   WeiZhengXiang  ")
fmt.Println(space)//将字符串两边指定的字符去掉
trim := strings.Trim("!wzx!-", "!")
fmt.Println(trim)//指定字符串左右边指定字符去掉
left := strings.TrimLeft("!sndjgn!", "!")
right := strings.TrimRight("!sndjgn!", "!")
fmt.Println(left)
fmt.Println(right)//判断字符串是否以指定的字符开头
prefix := strings.HasPrefix("https://www.bilibili.com/video/"+"BV1ng41147AT/?p=70&spm_id_from=333.1007.top_right_"+"bar_window_history.content.click&vd_"+"source=546576a6f524d3e58d9b93d26e97c920", "https")
fmt.Println("判断字符串是否以指定的子串开头", prefix)
时间函数:
func main() {now := time.Now()fmt.Println(now)fmt.Println(now.Second())fmt.Println(now.Year())december := time.Decemberfmt.Println(int(december))fmt.Println(now.Month())fmt.Println(now.Second())//将获得的时间存储起来,方便使用result := fmt.Sprintf("%d-%d-%d  %d:%d:%d", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Month(), now.Second())fmt.Println(result)//时间格式化format := now.Format("Mon Jan 2 15:04:05 -0700 MST 2006")fmt.Println(format)//2006-01-02 15:04:05format2 := now.Format("2006-01-02 15:04:05")fmt.Println(format2)}
new函数:

分配内存,主要分配值类型(int系列,float系列,bool,string,数组和结构体struct)

i := new(int)
fmt.Printf("类型%T,数值%v地址%v指针指向的值%v", i, i, &i, *i)

defer+recover机制处理错误,自定义错误:

defer+recover机制处理错误

func test(num, num1 int) int {defer func() {//使用recover内置函数捕获错误err := recover()//如果不等于nil则捕获错误    没有捕获到错误的话值默认值是零值:nilif err != nil {fmt.Println("捕获到的错误是:", err)}}()return num / num1
}func main() {//i := new(int)//fmt.Printf("类型%T,数值%v地址%v指针指向的值%v", i, i, &i, *i)//fmt.Println()var num = 10var num1 = 0test(num, num1)
}

自定义错误:

func test(num, num1 int) error {if num1 == 0 {err := errors.New("除数不能等于0")//掉用panic函数,将函数停止,后面的程序将不再执行fmt.Println("aaaaaaaaaaaaaaaaaaaaaaaaaaa")return err}return nil
}func main() {//i := new(int)//fmt.Printf("类型%T,数值%v地址%v指针指向的值%v", i, i, &i, *i)//fmt.Println()var num = 10var num1 = 0err := test(num, num1)if err != nil {fmt.Println(err)//如果将下面这行注掉程序会继续往下面执行panic(err)}fmt.Println("bbbbbbbbbbbbbb")
}

数组array:

注意:数组的长度是数组类型的一部分

数组的遍历:

1、普通for循环

2、是用for range(go所特有的key value遍历方式)

数组初始化四种方式:

//数组初始化一
var nums0 []int = []int{1, 2, 3}
fmt.Println(nums0)
//数组初始化二
var nums1 = []int{1, 2, 3}
fmt.Println(nums1)
//数组初始化三
var nums2 = [...]int{1, 2, 3}
fmt.Println(nums2)
//数组初始化四
var nums3 = [...]int{0: 1, 1: 2, 2: 3}
fmt.Println(nums3)

切片slice:

长度!=容量

// 切片练习
func main() {var array = [4]int{1, 2, 3, 4}var slice []intslice = array[0:3]fmt.Println(len(slice))fmt.Println(cap(slice))
}

切片会改变原数组切片中的数值

调用append函数给切片追加数据 调用该函数后切片会指向一个新的数组地址

func main() {var array = [4]int{1, 2, 3, 4}var slice []intslice = array[0:3]fmt.Println(len(slice))fmt.Println(cap(slice))//切片会改变原数组切片中的数值//原数组中的array[0]的值由原来的1变为10slice[0] = 10fmt.Println(array)//append函数 调用该函数后切片会指向一个新的数组地址slice = append(slice, 3, 4, 120)fmt.Println(slice)fmt.Println(array)}

切片拷贝切片追加:

// 切片练习
func main() {var array = [4]int{1, 2, 3, 4}var slice []intslice = array[0:3]fmt.Println(len(slice))fmt.Println(cap(slice))//切片会改变原数组切片中的数值slice[0] = 10fmt.Println(array)//append函数 调用该函数后切片会指向一个新的数组地址slice = append(slice, 3, 4, 120)fmt.Println(slice)fmt.Println(array)//使用make自定义切片  参数:数据类型  切片长度  切片容量slice2 := make([]int, 4, 5)fmt.Println(slice2)//切片后面追加切片 另一个切片后面附上三个点slice = append(slice, slice2...)fmt.Println(slice)//切片的拷贝var slice3 = make([]int, 10)//将后者拷贝到前者中copy(slice3, slice)fmt.Println(slice3)
}

映射map:

map集合在使用之前一定要make

map的key-value是无序的

key是不可以重复的,如果遇到重复,后一个value会替换前一个value

value可以重复

map的三种创建方式:

//1
var map1 = make(map[int]string, 10)
fmt.Println(map1)
//2
var map2 = make(map[int]string)
fmt.Println(map2)
//3
var map3 = map[int]string{1: "2323",2: "23232",3: "skewje",
}
fmt.Println(map3)

map集合的基本操作:

//3var map3 = map[int]string{1: "2323",2: "23232",3: "skewje",}
//删除一个元素
delete(map3, 1)
fmt.Println(map3)
//go中没有一个一次性删除全部map的方法
//删除操作1:逐一删除  2,附一个空的map将原来的抛弃
//2
map3 = make(map[int]string)
fmt.Println(map3)

对象struct:

go语言面向对象说明:

go也支持面向对象编程(oop),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言,所以我们说golang支持面向对象编程特性是比较准确的。

go没有类,go语言结构体和其他编程语言的类有同等的地位,你可以理解golang是基于struct来实现oop特性的。

go面向对象编程非常简洁,去掉了传统oop语言的方法重载,构造函数和析构函数,隐藏的this指针等等

go仍然有面向对象编程的继承,封装,多态的特性,只是实现方式和其他oop语言不一样,比如继承go没有extends关键字,继承是通过匿名字段实现。

type Teacher struct {Name stringAge  intJob  string
}func main() {//创建实例//方法一var a Teachera.Name = "魏正想"a.Age = 18a.Job = "农民"fmt.Println(a)//创建实例未赋值,默认为零值var b Teacherfmt.Println(b)//b := Teacher{//    Name: "",//    Age:  0,//    Job:  "",//}//方法二var c Teacher = Teacher{Name: "www", Age: 30, Job: "nnn"}fmt.Println(c)var e Teacher = Teacher{"www", 30, "nnn"}fmt.Println(e)//方法三://创建指针//new函数 分配内存,主要分配值类型(int系列,float系列,bool,string,数组和结构体struct)var d *Teacher = new(Teacher)d.Name = "111"d.Age = 22d.Job = "///"fmt.Println(*d)
}

结构体之间的转换:

1,需要满足结构体中数据字段类型,数量相同

2,转换时,要用到强制类型转换

接口:

go和Java的接口区别:

go的接口方法是被发现的,而Java语言的接口是需要对象继承并重写的

go接口:隐式实现:只要一个类型(结构体或其他)实现了接口中定义的所有方法,就自动实现了该接口

Java接口:显式实现:类必须声明实现了接口,并且必须实现接口中所有抽象方法(除非是抽象类)

//创建一个接口
type AnimalInter interface {sing()
}
// 创建结构体
type Cat struct {Name string
}type Dog struct {Name string
}func (c Cat) sing() {fmt.Println(c.Name, "在唱歌")
}func (c Dog) sing() {fmt.Println(c.Name, "在唱歌")
}func sing(c AnimalInter) {c.sing()
}func main() {var animal1 = Cat{Name: "cat"}var animal2 = Dog{Name: "dog"}sing(animal1)sing(animal2)
}

类型断言:

func sing(c AnimalInter) {//断言 判断接口对象是否是猫ch, ok := c.(Cat)fmt.Println(ch, ok)switch server := c.(type) {case Cat:fmt.Println(server)case Dog:fmt.Println(server)default:fmt.Println("我也不知道是个啥")}c.sing()//fmt.Println(c.getName())
}

空接口:

空接口能被任意调用

// 空接口
//第一种空接口方式
type EmpytInter interface {
}func Point(nn interface{}) {fmt.Println("你好")
}
//interface和any等价
//第二中空接口方式
func Point(nn any) {fmt.Println("你好")
}func main() {var animal1 = Cat{Name: "cat"}var animal2 = Dog{Name: "dog"}Point(animal1)
}

协程和channel

什么是协程?

  • Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时(runtime)管理。

  • 相比操作系统线程(thread),goroutine 更轻量,启动成本极低,可以轻松创建成千上万个。

  • Goroutine 运行在 Go 的并发模型之上,由 Go 调度器(scheduler)在少量操作系统线程上多路复用。

    第一种定义sync.WaitGroup变量的方法:

var wait sync.WaitGroup
//第一种定义sync.WaitGroup变量的方法func shopping(name string) {fmt.Println(name, "来购物")time.Sleep(1 * time.Second)fmt.Println(name, "购物结束")wait.Done()
}func main() {var now = time.Now()wait.Add(3)go shopping("张三")go shopping("里斯")go shopping("王五")wait.Wait()fmt.Println(time.Since(now))
}

第二种定义sync.WaitGroup变量的方法:

//函数中的参数都是值传递
func shopping(name string, wait *sync.WaitGroup) {fmt.Println(name, "来购物")time.Sleep(1 * time.Second)fmt.Println(name, "购物结束")wait.Done()
}func main() {var wait sync.WaitGroupvar now = time.Now()wait.Add(3)go shopping("张三", &wait)go shopping("里斯", &wait)go shopping("王五", &wait)wait.Wait()fmt.Println(time.Since(now))
}

使用channel来传递数据:

channel的作用**:**

Go 中的 channel(信道)是用于 *goroutine(协程)之间通信与同步 的主要机制,它提供了一种*类型安全、线程安全的数据传输方式,是 Go 并发模型(CSP 模型)的基石。

// channel知识
var moneyChan = make(chan int)func shopping(name string, money int, wait *sync.WaitGroup) {fmt.Println(name, "来购物")time.Sleep(1 * time.Second)//将钱放到信道中moneyChan <- moneyfmt.Println(name, "购物结束")wait.Done()
}func main() {var wait sync.WaitGroupvar now = time.Now()wait.Add(3)go shopping("张三", 2, &wait)go shopping("里斯", 4, &wait)go shopping("王五", 5, &wait)//创建匿名函数负责进行并行线程的监听,不能和下面的for循环调换顺序,否则启动不了该协程go func() {wait.Wait()close(moneyChan)}()//这段必须要有,信道信息有人传还要有人接!!!for {money, ok := <-moneyChanfmt.Println(money)if !ok {break}}//wait.Wait()fmt.Println(time.Since(now))
}
e(now))
}

使用channel来传递数据:

channel的作用**:**

Go 中的 channel(信道)是用于 *goroutine(协程)之间通信与同步 的主要机制,它提供了一种*类型安全、线程安全的数据传输方式,是 Go 并发模型(CSP 模型)的基石。

// channel知识
var moneyChan = make(chan int)func shopping(name string, money int, wait *sync.WaitGroup) {fmt.Println(name, "来购物")time.Sleep(1 * time.Second)//将钱放到信道中moneyChan <- moneyfmt.Println(name, "购物结束")wait.Done()
}func main() {var wait sync.WaitGroupvar now = time.Now()wait.Add(3)go shopping("张三", 2, &wait)go shopping("里斯", 4, &wait)go shopping("王五", 5, &wait)//创建匿名函数负责进行并行线程的监听,不能和下面的for循环调换顺序,否则启动不了该协程go func() {wait.Wait()close(moneyChan)}()//这段必须要有,信道信息有人传还要有人接!!!for {money, ok := <-moneyChanfmt.Println(money)if !ok {break}}//wait.Wait()fmt.Println(time.Since(now))
}
http://www.dtcms.com/a/585286.html

相关文章:

  • 360任意看地图网站网站开发设计需要什么证书
  • 大数据Spark(七十二):Transformation转换算子repartition和coalesce使用案例
  • Android 16 Kotlin协程 第二部分
  • 网站建设公司兴田德润电话新县城乡规划建设局网站
  • Claude Code使用指南
  • 如何进行MSSQL提权?默认库,xp_cmdshell提权
  • 第三章 布局
  • 「数据获取」《中国口岸年鉴》(2001-2024)(2002未出版)
  • Visual Studio笔记
  • 【开题答辩全过程】以 二手手机交易平台的设计与实现为例,包含答辩的问题和答案
  • “AI+XR”赋能智慧研创中心,预见职业教育“新双高”的未来
  • 保障房建设网站首页河北信息门户网站定制
  • MySQL的IFNULL函数介绍
  • 【数据结构】从零开始认识图论 --- 单源/多源最短路算法
  • 基于PyTorch的动物识别模型训练与应用实战
  • JS之BOM与DOM操作
  • 品牌企业网站案例wordpress 漂浮广告
  • 【人工智能学习笔记 三】 AI教学之前端跨栈一:React整体分层架构
  • 【ZeroRange WebRTC】WebRTC 在 IPC(网络摄像头)中的应用:架构、实现与实践(深入指南)
  • WiFi 热点启动失败问题排查与解决
  • 手写序列化与反序列化
  • T41NQ/T41N高性能低功耗SOC芯片 软硬件资料T41NQ适用于各种AIoT应用,适用于智能安防、智能家居,机器视觉等领域方案
  • 购物网站建设要求用wordpress改
  • vector 底层模拟实现(上):核心机制全解析 + 迭代器失效深度剖析
  • mysql内置函数——了解常用的函数
  • 网站建设步骤ppt一个企业seo网站的优化流程
  • 技术演进中的开发沉思-178 JSP :前世今生(下)
  • 做网站学什么软件网页美工实例教程
  • 深入理解 Spring Boot Actuator:构建可观测性与运维友好的应用
  • 现代C++的AI革命:C++20/C++23核心特性解析与实战应用