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
}

Go_day02的更多相关文章

随机推荐

  1. 函数调用_通过apply和call方法调用

    不同类型函数调用之间的主要区别在于:最终作为函数上下文(可以通过this参数隐式引用到)传递给执行函数对象不同.对于方法而言,即为所在的对象:对于函数而言是window或是undefined(取决于是 ...

  2. leetcode 655. 输出二叉树 【时间击败100.00%】 【内存击败96.49%】

    1 public List<List<String>> printTree(TreeNode root) { 2 ArrayList<List<String> ...

  3. 把一个元器件的原理图分成多个Part-转载

    (24条消息) [AD20]把一个元器件的原理图分成多个Part_不知道在干嘛每天的博客-CSDN博客_ad中原理图怎么分成几部分 以LM358芯片为例:把LM358原理图的A和B分开画,分成A和B两 ...

  4. Lua中__index元方法的介绍与使用

    一.相关介绍请参考:Lua中__index原方法介绍 二.使用示例 代码如下: 下面示例使用的元素迭代器 --1.列表元素迭代器,仅返回列表中每一个元素,改列表索引必须为连续的数字 function ...

  5. Java构造器详解

    java 构造器详解 一个构造器即使什么都不写 ,他也会默认存在一个构造器. 构造器的作用; ①:使用new关键字.本质是在调用构造器 ②:用来初始化值 定义了一个有参构造之后,如果想使用无参构造,显 ...

  6. 手把手教你用Burpsuite+夜神模拟器抓安卓(Android 7)http+https包

    (1)进入正题,bp证书下载(下载证书至电脑):打开bp,配置好代理,浏览器访问http://127.0.0.1:8080 下载证书,记住保存路径,注意别修改证书后缀(der)!!! (2)准备一个L ...

  7. kvm介绍(1)

  8. 【BOOK】【实例】【requests库+正则表达式】猫眼TOP100电影排名爬取

    猫眼电影TOP100页面爬取 https://maoyan.com/board/4 ##猫眼电影TOP100爬取 import requests import re import json impor ...

  9. flutter TextField 高度问题(包括使用maxlines自适应高度以及改变textfield组件自定义高度)

    先上代码. Container( color: Colors.blue, constraints: BoxConstraints( minHeight: 10, maxHeight: 20 ), ch ...

  10. Typora初学

    Markdown学习 TYPORA操作 Ctrl+Home 返回Typora顶部 Ctrl+End 返回Typora底部 Ctrl+T 创建表格 Ctrl+H 搜索并替换 Ctrl+Shift+M 公 ...