Go基础语法

流程控制

一共有三种:顺序结构,选择结构,循环结构

if语句

/*
if与else if的区别:
1:if无论是否满足条件都会向下执行,直到程序结束,else if 满足一个条件就会停止执行。
2:由于if都会执行一遍,则可能会同一个需要判断的事件,会进入2个if语句中,出现错误,而else if就不会发生这样的事情。
*/
func main() {
var a int = 15
var score int = 80
if a > 20 {
fmt.Println("a大于20")
}
if a > 10 {
fmt.Println("a大于10")
} if score >= 90 && score <= 100 {
fmt.Println("A")
} else if score >= 80 && score < 90 {
fmt.Println("B")
} else if score >= 70 && score < 80 {
fmt.Println("C")
} else if score >= 60 && score < 70 {
fmt.Println("D")
} else {
fmt.Println("F")
}
}

if嵌套

// 通过if嵌套实现二次验证密码
func main() {
var a, b int
var pwd int = 20221108 fmt.Print("请输入密码:")
fmt.Scan(&a)
if a == pwd {
fmt.Print("请再次输入密码:")
fmt.Scan(&b)
if b == pwd {
fmt.Println("登录成功")
} else {
fmt.Println("登录失败,密码输入不一致")
}
} else {
fmt.Println("密码错误")
}
}

switch语句

// switch语句
func main() {
var score int = 90 //case来匹配 switch后的结果
switch score {
case 90:
fmt.Print("A")
fallthrough //通过此关键字实现穿透
case 80:
fmt.Print("B")
//由于每一个case自带break效果 只能穿透到这里 如果继续穿透 需要再添加fallthrough
fallthrough
case 70, 60, 50:
//如果想过提前结束可以添加break
if score == 80 {
break
}
fmt.Print("C")
default:
fmt.Print("D")
} //switch的默认条件是 bool=ture
switch {
case false:
fmt.Print("false")
case true:
fmt.Print("true")
default:
fmt.Println("其他")
}
}

与java不同case后默认自带break效果 所以一般不存在穿透效果

所以需要使用fallthrough关键字来实现穿透效果

单独使用fallthrough会强制穿透,不管下一个case中的条件是否满足所以可以搭配break使用

for循环

func main() {
//循环10次
for i := 0; i < 10; i++ { //i的作用域只在for循环中哦
fmt.Println(i)
} //计算从1到10的和
sum := 0
for i := 1; i <= 10; i++ {
sum += i
}
fmt.Println(sum) j := 0
for j < 110 {
fmt.Println(j)
j++
} }

for循环中的所有参数都可以省略有这么几种情况:

1、for :循环条件: 这样需要声明变量起始值 并在循环体中控制 变量的增减

2、for {} 这就是无限循环

练习

func main() {
//打印一个 5*5的星号方阵
fmt.Println("5*5的星号方阵哦")
for i := 1; i <= 5; i++ {
for i := 1; i <= 5; i++ {
fmt.Print(" *")
}
fmt.Println()
} //打印九九乘法表
fmt.Println("九九乘法表")
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d*%d=%d/t", j, i, i*j)
}
fmt.Println()
}
//这样也是可行的 不过效率就降低了
for i := 1; i <= 9; i++ {
for j := 1; j <= 9; j++ {
if j > i {
break
}
fmt.Printf("%d*%d=%d/t", j, i, i*j)
}
fmt.Println()
} }

break 与 continue

func main() {

   //break是直接结束本循环程序
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
} //continue跳过本次循环
for i := 0; i < 10; i++ {
if i == 5 {
continue
}
fmt.Println(i)
}
}

string

func main() {
str := "hello,my country"
fmt.Println(str) //获取字符串的长度
fmt.Println("字符串的长度为:", len(str)) //获取字符串指定的字节
fmt.Println("字节打印:", str[2]) //acsii编码值108
fmt.Printf("%c\n", str[2]) //for循环遍历字符串
for i := 0; i < len(str); i++ {
fmt.Printf("%c", str[i])
} for i, j := range str {//i 是字符串下标 j是字节
fmt.Print(i)
fmt.Printf("%c", j)
}
}

string中的字节不能被单独改变

函数

函数是基本的代码块 用于执行一个任务

func 函数名 (参数1,参数2,...)返回值类型 int,int,...{
函数体
return 返回结果
}
  • 无参无返回值、几个或没有参及返回值
func main() {

   fmt.Println(add(2, 3))
printinfo()
printinfo2("你好")
a, b := printinfo3("世界", "你好")
fmt.Println(a, b) } func printinfo() {
fmt.Println("我是无参无返回值")
} func printinfo2(str string) {
fmt.Println("我是有参无返回值", str)
} func printinfo3(str, st2 string) (string, string) {
return st2, str
} func add(a, b int) int {
c := a + b
return c
}

可变参数

func main() {
getSum(2, 56, 23, 12, 4, 2) } // 可变参数
func getSum(nums ...int) { //意为可变参数其实是一个数组?
sum := 0
for i := 0; i < len(nums); i++ {
sum += nums[i] }
fmt.Println(sum)
}
  • 这里可以看到 可变参数是如何定义的 变量名...数据类型
  • 其次通过调用函数,发现可变参数可以一直输入变量,所以可变参数要定义再最后
  • 而且同java 可变参数有且只有一个

值传递、引用传递

值传递 对象有基本类型 int string bool float array

/*
值传递 将arr中的值复制一份到arr2上 即开辟了两个空间
所以修改arr2中的元素并不会影响arr
使用值传递的数据有 基础类型,array,struct
*/
func main() {
//值传递
arr := [4]int{1, 2, 3, 4}
update(arr)
fmt.Println(arr)
fmt.Println("========================") str := "世界"
updateString(str)
fmt.Println(str) //引用地址传递
} func update(arr2 [4]int) {
fmt.Println(arr2)
arr2[0] = 100
fmt.Println(arr2)
} func updateString(str string) {
fmt.Println(str)
str = "你好"
fmt.Println(str)
}

引用类型 对象有 slice map chan...

/*
s1 与s2指向的空间是同一个 s2修改了一个值
s1也会随之变化
*/ func main() {
//切片 其实就是可以扩容的数组
s1 := []int{1, 2, 3, 4}
update2(s1)
fmt.Println(s1) } func update2(s2 []int) {
fmt.Println("传递的数据:", s2)
s2[0] = 100
fmt.Println("更新后:", s2)
}

变量作用域

  • 在函数中定义的变量叫做局部变量
  • 在函数外定义的变量叫做全局变量
// 定义全局变量
var num int = 100 func main() {
temp := 199 if b := 1; b < 10 {
temp := 99
num := 00
fmt.Println(temp) //遵循就近原则 99
fmt.Println(b)
fmt.Println(num) //0
}
fmt.Println(temp) // 199
//fmt.Println(b) b只能在if中使用 fmt.Println(num)
} func f1() {
num := 11
a := 1
fmt.Println(a)
fmt.Println(num) //11
} func f2() {
//fmt.Println(a) 不能使用其他函数中定义的变量
fmt.Println(num) //100
}
  • 一定要注意变量的作用域

defer 延迟执行

  • defer的作用同队列一样 先入后出
  • 当然并不意味着defer标识的函数会最后传入参数执行,程序还是顺序传入参数 然后最后执行
func main() {
a := 10
fmt.Println(a) //10
//参数 10传递进去了,不过被延迟到最后执行
defer f(a) // 10
a++
fmt.Println("我在defer后", a) // 11
} func f(s int) {
fmt.Println(s)
}

函数的理解

函数本身也是数据类型,所以函数也是变量,可以复制

func main() {
fmt.Println(f1) //f1在不加()下使用就是一个变量
fmt.Printf("%T\n", f1) //类型是func(int, int) 定义的函数是什么样的 类型就是什么样的
//定义一个函数类型变量
var f2 func(int, int) = f1
f2(2, 3) //输出 为 2 3 证明 f1 的值赋予了f2
fmt.Printf("%T\n", f2) //func(int, int)
fmt.Println(f2) //地址与f1一致 指向同一个空间 0x69fe60 } func f1(a, b int) {
fmt.Println(a, b)
}

匿名函数 go是可以函数式编程的

func main() {
ff1() //调用f1函数
ff2 := ff1 //将f1变量的值赋予f2
ff2() //匿名函数
func() {
fmt.Println("我是匿名函数")
}() //匿名函数自己调用自动 //匿名函数同普通函数一样可以添加参数、返回值
x := func(a, b int) int {
fmt.Println("我是匿名函数", a, b)
return a + b
}(1, 2) fmt.Println(x) } func ff1() {
fmt.Println("f1")
}

回调函数

  • 高阶函数 接受一个函数作为参数的函数
  • 回调函数 作为一个参数的函数
func main() {
//r := sum(1, 2)
//fmt.Println(r)
r1 := opear(1, 2, sum)
fmt.Println(r1) r2 := opear(3, 6, mul)
fmt.Println(r2) r3 := opear(4, 7, func(a int, b int) int {
return a * b
})
fmt.Println(r3) r4 := opear(8, 4, func(a int, b int) int {
if b == 0 {
return 0
}
return a / b })
fmt.Println(r4) } func sum(a, b int) int {
return a + b
} func mul(a int, b int) int {
return a - b
} func opear(a, b int, fun func(int, int) int) int {
r := fun(a, b)
return r
}

闭包

函数调用函数就会生成一个结构:闭包

一个外层函数,内有一个内层函数,内层函数会操作外层函数的局部变量

并且这个外层函数的返回值就是这个内存函数 这就是闭包结构

*一般来说当函数调用完毕 函数中的变量等应该会被销毁,但是闭包结构中的外层函数的局部变量不会随着外层函数的结束而销毁,因为内层函数还在继续使用

func main() {
r1 := inc()
fmt.Println(r1) v1 := r1() //1
fmt.Println(v1) //1
v2 := r1() //2
fmt.Println(v2) //2
fmt.Println(r1()) //3
fmt.Println(r1()) //4
fmt.Println(r1()) //5 //i重新计数
r2 := inc()
fmt.Println(r2)
v3 := r2() //1
fmt.Println(v3) //1
fmt.Println(r1()) //6
fmt.Println(r2()) //2 } func inc() func() int { //外层函数
//局部变量
i := 0
//定义一个匿名函数,给变量自增并返回
fun := func() int { //内层函数
i++ //操作外层函数局部变量
return i
}
return fun
}

最新文章

  1. iOS 开发总结(上)
  2. python学习笔记-(六)深copy&amp;浅copy
  3. DbInitializer.cs初始化过程中context.entityName.Add()遇到的类型不匹配错误
  4. 用 Python 和 OpenCV 检测图片上的条形码
  5. @Param注解在mybatis中的使用以及传入参数的几种方式(转)
  6. sql server 2012 如何收缩事务日志
  7. TCP/IP之大明王朝邮差
  8. Android 适配多种ROM的快捷方式
  9. map的详细用法
  10. Mysql创建删除索引
  11. 同一个View双击事件&amp;&amp;单击事件
  12. Javascript 字符串浏览器兼容问题
  13. erlang supervisor说明
  14. QML中多样化的ListModel(MultiDelegate)
  15. Docker Machine 简介
  16. php简明学习笔记
  17. Linux系列教程(二十一)——Linux的bash基本功能
  18. Keepalived学习笔记
  19. 将Tomcat配置到你的mac电脑上,命令行启动tomcat
  20. vuex 的基本使用之Module

热门文章

  1. Path类,文件操作的路径用法
  2. drf从入门到飞升仙界 07
  3. linux创建数据库以及数据库用户密码
  4. FTP为什么越来越不好用了?要如何替代?
  5. Python3之并发(五)---线程条件(Condition)和事件(Event)
  6. vim ctrl+s 不能再操作
  7. JavaScript判断是否包含中文字符
  8. Yii2安装步骤
  9. sync.WaitGroup
  10. 根据指定月份,打印该月份所属的季节。 3,4,5 春季 6,7,8 夏季 9,10,11 秋季 12, 1, 2 冬季 if和switch各写一版