Go基础语法【快速入门】
文章目录
一、Go的安装
1.1 Windows系统
我最开始用的Windows系统学的go,但是后来转了Linux
安装方法:
前往Go官网下载安装包(后缀为msi
)
或者去Go中文社区下载
下载完运行,一直下一步就可以
在配置Go
的一些环境
1.2 Linux系统
同上下载安装包**(tar.gz
)**
将安装包移动到/usr/local
下
$ sudo mv 安装包名称 /usr/local
使用命令解压安装包:
$ tar -zxvf 下载的go安装包名称
配置环境:
在环境变量配置
文件/etc/profile
中添加以下内容:
打开文件命令:
$ sudo vim /etc/profile
# Go PATH
export PATH=$PATH:/usr/local/go/bin
输入----->按i
进行编辑,完成后按esc
退出编辑,输入:wq
退出
让配置文件生效:
$ source /etc/profile
查看Go版本
$ go version
若显示Go版本就表示成功了
1.3 Go Modules和代理
Go Modules是Go语言依赖管理解决方案。
Go.mod是Golang1.11版本新引入的官方包管理工具用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。
Go.mod其实就是一个Modules,Modules是相关Go包的集合,是源代码交换和版本控制的单元。
一个源代码目录甚至是空目录都可以作为Modules,只要其中包含有go.mod文件
1.3.1 第一步,mod文件字段内容
go.mod是启用了Go moduels的项目所必需的最重要的文件,它描述了当前项目(当前模块)的元信息,每一行都以一个动词开头。目前有以下5个动词
- module:用于定义当前项目的模块路径
- go:用于设置预期的Go版本。
- require:用于设置一个特定的模块版本。
- exclude:用于从使用中排除一个特定的模块版本。
- replace:用于将一个模块版本替换为另外一个模块版本。
1.3.2 第二步,生成go.mod
# 打开Go modules
go env -w GO111MODULE=on
# 设置GOPROXY 镜像源 用国内的
go env -w GOPROXY=https://goproxy.cn,direct
在go文件夹创建一个hello.go
的文件。文件内容如下:
package main
import "fmt"
func main(){
fmt.Println("Hello World!")
}
在项目根目录生成go.mod文件
$ cd 文件路径
$ go mod init hello(模板名称)
1.3.3 第三步,Go modules常用命令
用go get
拉取依赖
# 拉去最新版本
$ go get //地址
# 拉取指定版本
$ go get //地址+版本号
# 更新所有依赖
$ go get -u
# 整理现有的依赖
$ go mod tidy
# 查看现有的依赖结构
$ go mod graph
# 生成go.mod文件(唯一可以生成go.mod文件的子命令)
$ go mod init
# 编辑go.mod文件
$ go mod edit
# 导出现有的所有依赖
$ go mod vendor
# 校验一个模块是否被篡改过
$ go mod verify
二、基础语法
2.1第一个go程序
在控制台打印输出hello world
package main
import "fmt"
func main(){
fmt.Println("hello world")
}
2.1.1 将go程序编译为可执行文件
Windows 系统编译为
.exe
文件Linux 系统为二进制文件
2.1.1.1 编译单个文件
# 进入需要编译的文件目录
$ cd 目录地址
# 编译文件
$ go build XXX.go
2.1.1.2 编译整个项目
# 进入项目更目录
$ cd 地址
# 进行编译
$ go build
2.2 变量
在
go
里面 定义的变量必须要用,如果你不想用可以使用_
为变量名
2.2.1 匿名变量
package main
import "fmt"
func foo() (int, int) {
return 1, 2
}
//匿名函数用于后面函数 固定返回两个值,但是我们只需要一个数据 可以使用匿名函数将数值隐下去
/*
用_作为匿名函数
*/
func main() {
var a, _ = foo()
fmt.Println(a)
}
2.2.2 变量定义
// go变量定义
package main
import (
"fmt"
"time"
)
var x = "我是全局变量"
func name() {
fmt.Println(x, ",这是name函数调用")
}
func bar() {
fmt.Println(x, ",这是bar函数调用")
}
func main() {
bar()
name()
// 声明一个变量 var 变量名 = 值
var one = 1
var two = 2
var zreo int
fmt.Println(zreo) //声明未赋值 默认是0
fmt.Println(one + two)
// 数据类型声明可以不用
var name string = "张天昊"
var ts bool = true
fmt.Println(name, ts)
zreo = 10
fmt.Println(zreo + 1)
zreo = 40
fmt.Println(zreo + 2)
zreo = 30
fmt.Println(zreo + 3)
// go 有一个自己的回收机制
// 同时声明多个变量
var (
old int //0
ssq string //""
tf bool //false
)
//old = 10
//ssq = "ssq"
//tf = true
fmt.Println(old, ssq, tf)
sums()
// 声明并且赋值的简洁写法 只能在函数内部使用
name2 := "张"
fmt.Println(name2)
all()
time.Sleep(5 * time.Second)
}
func sums() {
var name = "函数sums"
fmt.Println(name)
}
func all() {
// 一行声明多个变量
var name, age, isMarild = "zhang", 23, false
fmt.Println(name, age, isMarild)
}
2.3 值拷贝
这是
go
语言的一个特性,与python
等动态语言不一样
go
中每个变量是不同的地址
package main
import "fmt"
func main() {
//与python不同 python一变则全变
//go中为拷贝 是完全不同的内存地址
var x = 10
var y = x
x = 20
//x= 20 y= 10
fmt.Println("x=", x, "y=", y)
sum()
}
func sum() {
var a = 1 + 1
var b = a
var c = a * b
fmt.Println(a, b, c)
}
2.4 基本数据类型
在
go
语言中数据类型分为了**基本数据
和复杂数据类型
**
数据类型 | 取值范围 |
---|---|
bool | true 或 false |
string | 任何UTF-8编码字符串 |
int | 有符号整数,取值范围为 -2147483648 至 2147483647 |
int8 | 有符号8位整数,取值范围为 -128 至 127 |
int16 | 有符号16位整数,取值范围为 -32768 至 32767 |
int32 | 有符号32位整数,取值范围为 -2147483648 至 2147483647 |
int64 | 有符号64位整数,取值范围为 -9223372036854775808 至 9223372036854775807 |
uint | 无符号整数,取值范围为 0 至 4294967295 |
uint8 | 无符号8位整数,取值范围为 0 至 255 |
uint16 | 无符号16位整数,取值范围为 0 至 65535 |
uint32 | 无符号32位整数,取值范围为 0 至 4294967295 |
uint64 | 无符号64位整数,取值范围为 0 至 18446744073709551615 |
uintptr | 无符号整数,用于存储一个指针 |
float32 | 32位浮点数 |
float64 | 64位浮点数 |
complex64 | 由32位实数和32位虚数组成的复数 |
complex128 | 由64位实数和64位虚数组成的复数 |
2.4.1 转义符
\ | 反斜杠用于转义下一个字符 |
---|---|
’ | 单引号用于在单引号括起的字符字面值中表示单引号字符 |
" | 双引号用于在双引号括起的字符串字面值中表示双引号字符 |
\a | 蜂鸣声符 |
\b | 退格符,将当前位置移到前一列 |
\f | 换页符,将当前位置移到下页开头 |
\n | 换行符,将当前位置移到下一行开头 |
\r | 回车符,将当前位置移到本行开头 |
\t | 水平制表符,将当前位置移到下一个制表符位置 |
\v | 垂直制表符,将当前位置移到下一垂直制表符位置 |
\xhh | 十六进制转义符,其中 hh 代表一个或多个表示十六进制值的数字 |
2.4.2 占位符
占位符 | 用途 |
---|---|
%v | 根据变量的值来输出 |
%+v | 在 %v 基础上,对结构体、切片等类型,将字段名与值一起输出 |
%#v | 输出值的 Go 语法表示方式 |
%T | 输出变量的类型 |
%% | 输出百分号本身,不进行任何格式化操作 |
%t | 输出 bool 类型变量 |
%d or %i | 输出十进制整数 |
%o | 输出八进制数 |
%x or %X | 输出十六进制数 |
%U | 输出 Unicode 字符集格式 |
%e or %E | 输出浮点型数据的科学计数法表示 |
%f | 输出浮点型数据的标准计数法表示 |
%q | 输出双引号引起来的字符串 |
%s | 输出字符串 |
2.4.3整型
package main
import (
"fmt"
//reflect 为打印数据类型的包
"reflect"
)
func main() {
//整形
/*
int8 : -127~127 \\\\\2的8次方个数
uint8 : 0~255
等等
int 在32位系统上就用的int32
int 在64位系统上就用的int64
int8: 一个字节 [-127~128]
uint8 : 从0开始[0~255]
*/
var s int
var i int8
....
}
2.4.4 浮点型
package main
import (
"fmt"
"reflect"
)
func main(){
/*
浮点型
float类型
float类型分为float32和float64两种类型,这两种浮点型数据格式遵循 IEEE 754 标准。
单精度浮点数占用4个字节(32位)存储空间来存储一个浮点数。而双精度浮点数使用 8个字节(64位)存储空间来存储一个浮点数。
单精度浮点数最多有7位十进制有效数字,如果某个数的有效数字位数超过7位,当把它定义为单精度变量时,超出的部分会自动四舍五入。双精度浮点数可以表示十进制的15或16位有效数字,超出的部分也会自动四舍五入。
浮点类型默认声明为float64。
*/
var f1 float32
f1 = 3.15487464
//reflect.TypeOf 打印数据类型
fmt.Println(f1, reflect.TypeOf(f1))
}
2.4.5 布尔型
package main
import (
"fmt"
"reflect"
)
func main(){
/*
布尔类型
布尔类型是最基本数据类型之一,只有两个值:true和false,分别代表逻辑判断中的真和假,主要应用在条件判断中
*/
var b bool // 声明b是一个布尔类型
b = true
b = false // 该类型只有true和false两个值,分别代表真假两种状态
fmt.Println(b, reflect.TypeOf(b))
fmt.Println(1 == 1) // 比较运算符的结果是一个布尔值
// fmt.Println(1 == "1") // 报错,mismatched types不能比较
fmt.Println(3 > 1)
var name = "yuan"
var b2 = name == "rain"
//false ****
fmt.Println(b2)
}
2.4.6 字符类型
package main
import (
"fmt"
"reflect"
)
func main(){
/*
字符串
字符串是最基本也是最常用的数据类型,是通过双引号将多个字符按串联起来的一种数据,用于展示文本
单引号只能标识字符
注意:
索引从零开始计数
go语言不支持负索引
*/
var s = "hello zhang"
fmt.Println(s)
// (1)索引取值 slice[index]
a := s[2]
fmt.Println(string(a))
// (2)切片取值slice[start:end], 取出的元素数量为:结束位置 - 开始位置;
b1 := s[2:5] //
fmt.Println(b1)
b2 := s[0:] // 当缺省结束位置时,表示从开始位置到整个连续区域末尾;
fmt.Println(b2)
b3 := s[:8] // 当缺省开始位置时,表示从连续区域开头到结束位置;
fmt.Println(b3)
// (3)字符串拼接
var s1 = "hello"
var s2 = "zhang"
var s3 = s1 + s2 // 生成一个新的字符串
fmt.Println(s3)
}
2.4.7 进制转换
package main
import (
"fmt"
)
func main(){
/*
进制转换
*/
// 十进制转化
var n int = 10
//printf 传输数据进去
fmt.Printf("%d \n", n) //%d 表示十进制
fmt.Printf("%o \n", n) // 占位符%o表示八进制
fmt.Printf("%b \n", n) //占位符%b表示二进制
fmt.Printf("%x \n", n) //占位符%x表示十六进制
// 八进制转化
var b int = 020
fmt.Printf("%o \n", b) // 20
fmt.Printf("%d \n", b) // 16
fmt.Printf("%x \n", b) // 10
fmt.Printf("%b \n", b) // 10000
// 十六进制转化
var c = 0x12
fmt.Printf("%d \n", c) // 18
fmt.Printf("%o \n", c) // 22
fmt.Printf("%x \n", c) // 12
fmt.Printf("%b \n", c) // 10010
}
2.5 字符串的常用方法
package main
import (
"fmt"
"reflect"
"strings"
)
/*
方法 介绍
len(str) 求长度
strings.ToUpper,strings.ToLower 生成一个新的全部大写的字符串,生成一个新的全部小写的字符串
strings.ReplaceAll 生成一个新的原字符串被指定替换后的字符串
strings.Contains 判断是否包含
strings.HasPrefix,strings.HasSuffix 前缀/后缀判断
strings.Trim、 去除字符串两端匹配的内容
strings.Index(),strings.LastIndex() 子串出现的位置
strings.Split 分割,将字符串按指定的内容分割成数组
strings.Join(a[]string, sep string) join操作,将数组按指定的内容拼接成字符串
*/
func main() {
//action
action()
}
func allstring() {
var a string
a = "hello,Zhang,tian,hao"
//获取字符串长度
fmt.Println(len(a))
// 一个全部大写的字符串
fmt.Println(strings.ToUpper(a))
//全部小写
fmt.Println(strings.ToLower(a))
// 判断是否包含
fmt.Println(strings.Contains(a, "tianhao"))
//前缀判断
fmt.Println(strings.HasPrefix(a, "zth"))
//后缀判断
fmt.Println(strings.HasSuffix(a, "hao"))
// 是否包含
fmt.Println(strings.Contains(a, "tian"))
// 去除字符串两端匹配的内容
s := strings.Trim(a, "o")
fmt.Println(s)
//子串出现的位置
fmt.Println(strings.Index(a, "Z")) //没有找到就返回-1
//最后一次出现的位置
fmt.Println(strings.LastIndex(a, "o"))
//分割,将字符串按指定的内容分割成数组
a2 := strings.Split(a, ",")
//fmt.Println(reflect.TypeOf(a2))
fmt.Println(a2)
//将数组拼接成字符串
var set = strings.Join(a2, "-")
fmt.Println(set, "\n", reflect.TypeOf(set))
}
func action() {
s := "mysql … -u root -p 123"
uindex := strings.Index(s, "-u")
pindex := strings.Index(s, "-p")
user := s[uindex+3 : pindex-1]
psd := s[pindex+3:]
fmt.Println("用户名为", user, "密码为", psd)
}
2.6 数据类型转换
package main
import (
"fmt"
"reflect"
"strconv"
)
func main() {
//(1)整型之间的转换 int8 int16
var x int8 = 10
var y int16 = 20
fmt.Println(x + int8(y))
// (2)字符串与整型之间的转换 strconv库
var agestr = "32"
//var name = 12
//字符串转整型
var age, _ = strconv.Atoi(agestr)
fmt.Println(age)
//fmt.Println("err: ", err) // <nil>空对象
price := 100
//整形转字符
price_str := strconv.Itoa(price)
fmt.Println(price_str, reflect.TypeOf(price_str))
//strconv parse系列函数
//字符串转整型 base进制 bitSize是比特位 8---int8
ret, _ := strconv.ParseInt("28", 10, 8)
fmt.Println(ret, reflect.TypeOf(ret))
//字符串转换为浮点型
floats, _ := strconv.ParseFloat("3.1415926", 64)
fmt.Println(floats, reflect.TypeOf(floats))
//字符串转换为布尔值
b, _ := strconv.ParseBool("0")
b1, _ := strconv.ParseBool("-1")
b2, _ := strconv.ParseBool("true")
b3, _ := strconv.ParseBool("T")
fmt.Println(b, b1, b2, b3)
}
2.7 运算符
运算符 | 描述 |
---|---|
算数运算符 | 用于执行基本的数学运算,如加法、减法、乘法和除法 |
+ | 加法运算符,将两个数相加 |
- | 减法运算符,从第一个数中减去第二个数 |
* | 乘法运算符,将两个数相乘 |
/ | 除法运算符,将第一个数除以第二个数 |
% | 取模运算符,返回第一个数除以第二个数的余数 |
自增和自减运算符 | 自增或自减运算符用于递增或递减变量的值 |
++ | 自增运算符,将变量的值加一 |
– | 自减运算符,将变量的值减一 |
比较运算符 | 用于比较两个值之间的关系,返回一个布尔值 |
== | 等于运算符,如果两个值相等则返回 true,否则返回 false |
!= | 不等于运算符,如果两个值不相等则返回 true,否则返回 false |
> | 大于运算符,如果左边的值大于右边的值则返回 true,否则返回 false |
< | 小于运算符,如果左边的值小于右边的值则返回 true,否则返回 false |
>= | 大于等于运算符,如果左边的值大于等于右边的值则返回 true,否则返回 false |
<= | 小于等于运算符,如果左边的值小于等于右边的值则返回 true,否则返回 false |
逻辑运算符 | 用于执行逻辑运算,如AND、OR、和NOT |
&& | 逻辑 AND 运算符,两个操作数都为 true 时才返回 true,否则返回 false |
|| | 逻辑 OR 运算符,两个操作数有一个为 true 时返回 true,否则返回 false |
! | 逻辑 NOT 运算符,如果条件为 true 则返回 false,否则返回 true |
位运算符 | 用于执行二进制位运算,例如 按位与、按位或、按位异或等 |
& | 按位 AND 运算符,参与运算的两个值都为 1 时才返回 1,否则返回 0 |
| | 按位 OR 运算符,参与运算的两个值有一个为 1 时就返回 1,否则返回 0 |
^ | 按位异或运算符,参与运算的两个值只有一个为 1 时才返回 1,否则返回 0 |
<< | 左移运算符,将第一个操作数的二进制位向左移动第二个操作数指定的位数 |
>> | 右移运算符,将第一个操作数的二进制位向右移动第二个操作数指定的位数 |
赋值运算符 | 用于将一个值赋给一个变量或表达式 |
= | 简单赋值运算符,将右边表达式的值赋给左边的变量 |
+= | 加法赋值运算符,等价于 a = a + b |
-= | 减法赋值运算符,等价于 a = a - b |
*= | 乘法赋值运算符,等价于 a = a * b |
/= | 除法赋值运算符,等价于 a = a / b |
%= | 取余赋值运算符,等价于 a = a % b |
<<= | 左移赋值运算符,等价于 a = a << b |
>>= | 右移赋值运算符,等价于 a = a >> b |
&= | 按位 AND 赋值运算符,等价于 a = a & b |
package main
import "fmt"
func main() {
// 和python运算符一样
//计算一个数是为奇数还是偶数
x, y := 10, 20
fmt.Println(x%2 == 0, y)
//关系运算符 与python相同 == != >= <= 返回布尔值
fmt.Println(x >= y)
//逻辑运算符
//与或非运算
/*
与&&: 真真-真,真假-假,假假-假 ,
或||: 真或真-真,真或假为真,假或假为假
非运算 !:非真为假,非假为真 取反
*/
fmt.Println(true && false)
fmt.Println(true || false)
fmt.Println(!true || false)
//database:root 123
username := "zhang"
password := 123
fmt.Println(username == "root" && password == 123)
/*
赋值运算
和python一样
*/
var a = 12
a += 1
fmt.Println(a)
var b = 10
//自加一
b++
fmt.Println(b)
//优先级
var q, w, z = 1, 2, 3
fmt.Println(q, w, z)
var t = q + w
fmt.Println(t)
}
2.8 输入输出函数
2.8.1 输出函数
go
中常用的输入输出函数,在fmt
包中
package main
import "fmt"
func main() {
//输出函数
//print println
var name, age = "yuan", 32
fmt.Println("hello world")
fmt.Println(name)
fmt.Println(age)
fmt.Println("姓名:", name, "年龄", age)
//fmt.Print(name)
//fmt.Print(age)
var isMarried = false
fmt.Printf("姓名:%s,年龄:%d,婚否:%t\n", name, age, isMarried)
//sprintf:
s := fmt.Sprintf("姓名:%s,年龄:%d,婚否:%t", name, age, isMarried)
fmt.Println(s)
}
2.8.2 输入函数
package main
import (
"fmt"
"strings"
)
func main() {
//输入函数 IO函数
scan()
}
func action() {
var (
birth string
)
fmt.Println("输入生日格式如:1988-3-16")
fmt.Scan(&birth)
birthslice := strings.Split(birth, "-")
fmt.Printf("您的生日是%s年-%s月-%s日", birthslice[0], birthslice[1], birthslice[2])
}
func scan() {
//(1)fmt.scan
//var name string
//var age int
//fmt.Scan(&name, &age)
//fmt.Println(name, age)
//(2)fmt.scanln
//(3)fmt.scanf 按照指定的格式输入
var a, b int
fmt.Scanf("%d+%d", &a, &b)
fmt.Println(a + b)
}
func action2() {
var name string
fmt.Println("请输入一个英文名: ")
fmt.Scan(&name)
var b = (strings.HasPrefix(name, "a")) || (strings.HasPrefix(name, "A"))
fmt.Println(b)
}
2.9 流程控制语句
2.9.1 if语句
package main
import "fmt"
func main() {
twoIf()
}
func twoIf() {
//双分支if else
var (
passworld any
input string
)
passworld = "123"
fmt.Println("输入密码:")
fmt.Scan(&input)
if passworld == input {
fmt.Println("密码正确")
} else {
fmt.Println("密码错误")
}
}
多分支
package main
import "fmt"
func main() {
weeks()
}
func scanres() {
//判断成绩
var scanre int
fmt.Println("输入你的成绩")
fmt.Scan(&scanre)
if scanre > 100 || scanre < 0 {
fmt.Println("输入数字不合法")
} else if scanre >= 90 {
fmt.Println("优秀")
} else if scanre >= 70 {
fmt.Println("良好")
} else if scanre >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
}
func weeks() {
var week int
fmt.Println("输入1-7的数字")
fmt.Scan(&week)
if week == 1 {
fmt.Printf("星期%d", week)
} else if week == 2 {
fmt.Printf("星期%d", week)
} else if week == 3 {
fmt.Printf("星期%d", week)
} else if week == 4 {
fmt.Printf("星期%d", week)
} else if week == 5 {
fmt.Printf("星期%d", week)
} else if week == 6 {
fmt.Printf("星期%d", week)
} else if week == 7 {
fmt.Printf("星期%d", week)
} else {
fmt.Println("非法输入")
}
}
2.9.2 switch语句
package main
import "fmt"
func main() {
weeks()
}
func weeks() {
switch week {
case 1:
fmt.Printf("星期%d", week)
case 2:
fmt.Printf("星期%d", week)
case 3:
fmt.Printf("星期%d", week)
case 4:
fmt.Printf("星期%d", week)
case 5:
fmt.Printf("星期%d", week)
case 6:
fmt.Printf("星期%d", week)
case 7:
fmt.Println("星期日")
default:
fmt.Println("非法输入")
}
}
2.9.3 流程控制语句练习
星座判断
package main
import "fmt"
func main() {
var (
month int
day int
xingZuo string
)
fmt.Println("输入月和日")
fmt.Scan(&month, &day)
if month > 12 && day > 31 && day < 1 {
fmt.Println("输入有误")
} else {
switch month {
case 1:
if day >= 1 && day <= 19 {
xingZuo = "摩羯座"
} else {
xingZuo = "水瓶座"
}
case 2:
// 日判断
if day >= 1 && day <= 18 {
xingZuo = "水瓶座"
} else {
xingZuo = "双鱼座"
}
case 3:
// 日判断
if day >= 1 && day <= 20 {
xingZuo = "双鱼座"
} else {
xingZuo = "白羊座"
}
case 4:
// 日判断
if day >= 1 && day <= 19 {
xingZuo = "白羊座"
} else {
xingZuo = "金牛座"
}
case 5:
// 日判断
if day >= 1 && day <= 20 {
xingZuo = "金牛座"
} else {
xingZuo = "双子座"
}
case 6:
// 日判断
if day >= 1 && day <= 21 {
xingZuo = "双子座"
} else {
xingZuo = "巨蟹座"
}
case 7:
// 日判断
if day >= 1 && day <= 22 {
xingZuo = "巨蟹座"
} else {
xingZuo = "狮子座"
}
case 8:
// 日判断
if day >= 1 && day <= 22 {
xingZuo = "狮子座"
} else {
xingZuo = "处女座"
}
case 9:
// 日判断
if day >= 1 && day <= 22 {
xingZuo = "处女座"
} else {
xingZuo = "天秤座"
}
case 10:
// 日判断
if day >= 1 && day <= 23 {
xingZuo = "天秤座"
} else {
xingZuo = "天蝎座"
}
case 11:
// 日判断
if day >= 1 && day <= 22 {
xingZuo = "天蝎座"
} else {
xingZuo = "射手座"
}
case 12:
// 日判断
if day >= 1 && day <= 21 {
xingZuo = "射手座"
} else {
xingZuo = "摩羯座"
}
default:
fmt.Println("输入的月份有问题")
}
fmt.Println("您的星座是:", xingZuo)
}
}
2.10 循环语句
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,
能否继续重复,决定循环的终止条件。与其它主流编程语言不同的的是,
Go
语言中的循环语句只支持for
关键字,而不支持while
和do-while
结构。
2.10.1 for循环
package main
import "fmt"
func main() {
//var a = 100
//for a > 0 {
// a--
// fmt.Println(a)
//}
// 三要素for循环
/*
var a = 100//初始语句
a > 0//条件语句
a--//步进语句
*/
//for count := 0; count < 10; count++ {
// fmt.Println(count)
//}
var s = 0
for i := 1; i <= 100; i++ {
s += i
}
fmt.Println(s)
}
2.10.2循环分支嵌套
package main
import "fmt"
func main() {
//for_switch()
//if_for()
}
func for_if() {
for count := 1; count <= 100; count++ {
if count%2 == 0 {
fmt.Println("偶数有:", count)
}
}
}
func if_for() {
var num int
fmt.Println("(1)从大到小,(2)从小到大")
fmt.Scan(&num)
if num == 1 {
for count := 1; count <= 100; count++ {
fmt.Println(count)
}
} else if num == 2 {
for count := 100; count <= 1; count-- {
fmt.Println(count)
}
} else {
fmt.Println("输入不规范")
}
}
2.10.3 退出循环
package main
import "fmt"
func main() {
//for_switch()
}
func breaks() {
for i := 0; i < 10; i++ {
if i == 6 {
break
}
fmt.Println(i)
}
fmt.Println("退出了循环")
}
func for_switch() {
var num int
fmt.Println(`
1,普通攻击
2,技能攻击
3,逃跑
4,求助
5,退出
`)
for true {
fmt.Scan(&num)
if num == 5 {
break
}
switch num {
case 1:
fmt.Println("普通攻击")
case 2:
fmt.Println("技能攻击")
case 3:
fmt.Println("逃跑")
case 4:
fmt.Println("求助")
default:
fmt.Println("输入有误")
}
}
}
func continues() {
for count := 0; count < 10; count++ {
if count == 6 {
continue
}
fmt.Println("这是continue", count)
}
}
func action() {
for i := 1; i <= 100; i++ {
}
}
2.11 复杂数据类型
以下为go语言常见复杂数据类型
数据类型 | 描述 |
---|---|
数组 | 存储具有相同数据类型的固定尺寸元素的连续集合 |
指针 | 通过数据地址取值,或者操作地址 |
切片 | 动态大小的、可变长度的序列,可以看作是对数组的抽象封装 |
映射(Map) | 一种无序的键值对的集合,其中所有的键都是唯一的 |
结构体 | 用于表示一组不同类型的数据的集合,通过一个唯一的名字来区分不同的字段 |
接口 | 一种类型,指定了一组方法的集合,可以实现多态的效果 |
通道(Channel) | 一种数据类型,用于在不同goroutine之间传递数据,类似于管道(pipe) |
2.11.1 指针类型
go的指针只有两个操作
& 变量 取址符 返回变量所在的地址
package main
import (
"fmt"
"reflect"
)
func main() {
//获取地址 &
//var x = 10
//fmt.Printf("赋值前x的地址%p\n", &x)
//x = 100
//fmt.Printf("赋值后的地址%p\n", &x)
var x = 10 //x称为整型变量
fmt.Println(&x, reflect.TypeOf(&x)) //地址是一个 *int(整型指针类型)
//地址赋值
var p *int
p = &x // 也可以var p =&x
fmt.Println(p, &p)
//取值操作 : *指针变量
fmt.Println(*p, reflect.TypeOf(*p))
*p = 100
fmt.Println(x)
//var a = 1
//var b = a //值拷贝
//b = 100 //不会影响a
// b影响a,a影响b(通过指针来实现)
//var b = &a
a = 102
//*b = 100
//fmt.Println(*b)
//指针案例3
var a = 100
var b = &a
var c = &b
**c = 200
fmt.Println(a)
}
2.11.1.1 new函数
package main
import "fmt"
func main() {
//指针属于引用类型
// 引用类型 当声明未赋值之前是没有开辟空间的,即没有默认值
// 要用new一个(类型)
var a = new(int)
*a = 10
fmt.Println(*a)
}
2.11.2 数组
2.11.2.1 数组的声明
// 数组的声明
var arr [5]int
fmt.Println(arr) //[0 0 0 0 0]
2.11.2.2 数组赋值
package main
import "fmt"
func main() {
// 数组的声明
var arr [5]int
fmt.Println(arr) //[0 0 0 0 0]
//赋值 数组[索引]
fmt.Println(arr[0])
fmt.Println(arr[1])
fmt.Println(arr[2])
//索引赋值
arr[0] = 25
fmt.Println(arr)
arr[1] = 26
arr[2] = 27
arr[3] = 28
fmt.Println(arr) //[25 26 27 28 0]
// 数组的声明并赋值
var names = [3]string{"ran", "zhang", "shi"}
fmt.Println(names)
var age = [3]int{1, 2, 3}
fmt.Println(age)
// 省略长度赋值
var name = [...]string{"ran", "zhang", "shi", "jjj", "aaa"}
fmt.Println(name)
//索引赋值
var name1 = [...]string{0: "zhang", 1: "shi"}
fmt.Println(name1)
//go len函数 :计算容器长度
fmt.Println(len(name))
}
2.11.2.3数组操作
2.11.2.3.1索引操作
var names = [3]string{"yuan", "rain", "alvin"}
//索引操作
fmt.Println(names[2])
names[2] = "Rain"
fmt.Println(names)
2.11.2.3.2切片操作
var arr = [...]int{11, 12, 13, 45, 75, 64, 78, 66, 54}
s := arr[0:3]
fmt.Println(s, reflect.TypeOf(s)) //[11 12 13] []int
s1 := arr[1:]
fmt.Println(s, reflect.TypeOf(s)) //[11 12 13] []int
s2 := arr[:3]
fmt.Println(s, reflect.TypeOf(s)) //[11 12 13] []int
s3 := arr[2:4]
fmt.Println(s, reflect.TypeOf(s)) //[11 12 13] []int
fmt.Println(s1, s2, s3)
2.11.2.3.3 遍历数组
var arr2 = [...]int{1, 2, 3, 4, 5}
for i, i2 := range arr2 {
// 相当于python中的en...函数
// i为下标 i2为数据
fmt.Println(i, i2)
}
fmt.Println("======================================================================")
//用for三要素提取
for i := 0; i < len(arr2); i++ {
fmt.Println(i, arr2[i])
}
2.11.2.3 切片
切片是对数组的引用
var a = [5]int{1, 2, 3, 4, 5}
var slice = a[:] //起始地址 长度 容量(cap)
fmt.Println(len(slice), cap(slice))
var slice2 = a[:2]
fmt.Println(len(slice2), cap(slice2))
newSlicec := slice[1:3]
newSlicec[1] = 1000 // [1 2 1000 4 5]
fmt.Println(a)
fmt.Println(slice) // [1 2 1000 4 5]
fmt.Println(slice2)
2.11.2.3.1 声明切片
// 直接声明切片
//arr := [5]int{10,11,12,13,14}
//s:=arr[:]
var s = []int{10, 11, 12, 13, 14}
fmt.Println(s)
s1 := s[1:4]
fmt.Println(len(s1), cap(s1))
s2 := s[3:]
fmt.Println(len(s2), cap(s2))
s3 := s1[1:2]
fmt.Println(len(s3), cap(s3))
示例:
func action() {
var a = [...]int{1, 2, 3, 4, 5, 6}
a1 := a[0:3]
a2 := a[0:5]
a3 := a[1:5]
fmt.Println(a1)
fmt.Println(a2)
fmt.Println(a3)
}
2.11.2.3.2 make函数
package main
import (
"fmt"
)
func main() {
//var s []int
//初始化创建空间 10为容量
var s = make([]int, 5, 10)
fmt.Println(len(s), cap(s))
fmt.Println(s)
s[0] = 100
fmt.Println(s)
}
2.11.2.4 map类型
相当于python的字典类型
在go中叫做map类型
-
先声明后赋值
c := make(map[string]string) c["name"] = "zhang" c["age"] = "18" fmt.Println(c)
-
直接声明赋值,
info := map[string]string{"name": "yuan", "age": "20", "city": "China"}
-
map增删改查
//查 info := map[string]string{"name": "yuan", "age": "20", "city": "China"} fmt.Println(info) Map() //改,增 info2 := map[string]string{"name": "yuan", "age": "18", "gender": "male"} m2 := Map02(info2) fmt.Println(m2) // 删 m3 := Map03(info2) fmt.Println(m3)
-
map容量
// map容量 m := make(map[string]float32, 100) m4 := Map04(m) fmt.Println(m4)
-
map的综合应用
func Map() { // map增删改查 // 通过key访问 查 info := map[string]string{"name": "yuan", "age": "18", "gender": "male"} val := info["name"] val, is_exist := info["name"] // 判断某个键是否存在map数据中 if is_exist { fmt.Println(val) fmt.Println(is_exist) } else { fmt.Println("键不存在!") } //循环访问所有键值 for s, s2 := range info { fmt.Println(s, s2) } noSortMap := map[int]int{ 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, } //range顺序随机 for i, i2 := range noSortMap { fmt.Println(i, i2) } } func Map02(s map[string]string) map[string]string { s["height"] = "180cm" // 键不存在,则是添加键值对 s["age"] = "22" // 键存在,则是更新键的值 return s // 利用函数写的map02输入map类型 返回map类型 } func Map03(s map[string]string) any { //删 delete(s, "name") return s } func Map04(s map[string]float32) any { // 容量 return len(s) } func Map05() { // map的灵活运用 data := map[string][]string{"hebei": []string{"廊坊市", "石家庄", "邯郸"}, "beijing": []string{"朝阳", "丰台", "海淀"}} // 打印河北的第二个城市 // 循环打印每个省份的名字和城市数量 // 添加一个新的省份和城市的key-value // 删除北京的key-value s := data["hebei"][1] fmt.Println("河北的第二个城市", s) for s2, _ := range data { for _, s3 := range data[s2] { fmt.Println(s2, len(data[s2]), s3) } } //ss := map[string][]string{"sicuan": {"meishan", "chengdu"}} //fmt.Println(ss) var zz = []string{"眉山", "成都"} data["chengdu"] = zz fmt.Println(data) delete(data, "beijing") fmt.Println(data) }
2.11.2.5 map底层原理
-
Go
语言中的Map
基本数据结构是一张哈希表,其中每个哈希表的元素是一个桶(Bucket
) -
桶(Bucket)
是一个包含一些键值对的可拓展数组(slicemap
),key
和value
都占用8个字节的空间。 -
当我们使用
Key
在Map中存储或获取值时,Go
语言中的Map
会自动进行哈希计算以获取桶索引,然后在对应的桶中查找对应的值。
需要注意的是,
Go
语言中的Map
底层实现可以随着版本、编译器和运行环境等因素的不同而略有差异。但是在任何情况下,Map
都会使用基于哈希表和桶的底层实现机制来实现其存储和查找功能。
2.11.2.6 append函数
append 追加值,给切片追加,在后面追加数据
package main
import "fmt"
func main() {
var s []int
//append 追加值,给切片追加,在后面追加数据
s1 := append(s, 1)
fmt.Println(s1)
s2 := append(s1, 2, 3, 4)
fmt.Println(s2)
var t = []int{2, 3, 4}
t1 := append(t, 1)
fmt.Println(t1)
var s4 = make([]int, 3, 10) //初始化完,[0 0 0]
s5 := append(s4, 100)
fmt.Println(s5) //[0 0 0 100]
//Append()
var c = 255
fmt.Println(c >> 10)
}
append 底层原理(面试题)
func Append() {
//append 重新开辟内存
var a1 = make([]int, 2, 10)
a2 := append(a1, 1, 23, 4)
fmt.Println(a1)
fmt.Println(a2)
//[0 0]
//[0 0 1 23 4]
//因为a1空间为2,所以给他添加3个内容时,append会重新开辟内存,
}
2.11.3 defer 语句
package main
import "fmt"
func cele(index string, a, b int) int {
res := a + b
fmt.Println(index, a, b, res)
return res
}
/*
defer 注册要延迟执行函数时,要先确定他所有参数的值
defer 分为两个顺序--->注册顺序和执行顺序
先注册:
defer cele("AA", x, cele("A", x, y))
defer cele("BB", x, cele("B", x, y))
最后执行:
defer cele("BB", x, cele("B", x, y))
defer cele("AA", x, cele("A", x, y))
1、cele("A",1,2) 返回3
2、cele("B",10,2) 返回12
3、cele("BB",10,12) 返回22
4、cele("AA",1,3) 返回4
代码执行结果是:
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
*/
func main() {
x, y := 1, 2
defer cele("AA", x, cele("A", x, y))
x = 10
defer cele("BB", x, cele("B", x, y))
y = 20
}
2.11.4 panic与recover 结合
在一个程序中只使用panic抛出异常会导致这个程序结束运行,但是与recover结合使用就不会—>recover必须要在defer语句里面才有用
只用panic
package main
import (
"fmt"
)
func fn1() {
fmt.Println("fn1")
}
func fn2() {
panic("抛出异常")
}
func fn3() {
fmt.Println("fn3")
}
func main() {
fn1()
fn2()
fn3()
}
/*
运行结果
fn1
panic: 抛出异常
goroutine 1 [running]:
main.fn2(...)
E:/PRC/cs/main.go:11
*/
与recover结合
package main
import (
"fmt"
)
func fn1() {
fmt.Println("fn1")
}
func fn2() {
defer func() {
err := recover()
if err != nil {
fmt.Println(err)
}
}()
panic("抛出异常")
}
func fn3() {
fmt.Println("fn3")
}
func main() {
fn1()
fn2()
fn3()
}
/*
程序输出:
fn1
抛出异常
fn3
*/
他也可以接收其他异常,不一定要在你的程序中写panic