昨日回顾

# 1 go 基础数据类型
-数字:整数,正整数,浮点数,复数
-字符串: "" ``
-单引号引起来的,只能放一个字符 a 中
-实际上是数字表示 20013
-默认是int32 实际上是rune
-也可定义为 byte类型或uint8类型
-布尔类型 :true,false # 2 常量 :后期不能修改
-作用域范围
-同时定义多个常量
-iota # 3 函数
-1 没有参数没有返回值 fun 函数名(){}
-2 有参数没有返回值 fun 函数名(a int){}
-3 多个参数同一种类型,可以简写 fun 函数名(a,b int){}
-4 多个参数同一种类型,有返回值可以简写 fun 函数名(a,b int)int{ retrun a+b}
-5 多个返回值fun 函数名(a,b int)(int,string){ retrun a+b,'成功'} # 4 函数高级
-1 匿名函数,定义在函数内部,没有名字
var f func()=func(){}
头等函数
一等公民
-2 闭包函数
-定义在函数内部,对外部作用域有引用 -3 函数也是一种类型,参数和返回值都是类型的一部分 -4 一个函数可以返回另一个函数 # 补充
go的值类型和引用类型。
装饰器是一种设计模式。go语言虽然没有装饰器语法糖,但还是可以实现装饰器。
设计模式还有装饰器模式、迭代器模式。

今日内容

1 函数高级

package main

import "fmt"

// 1 函数的参数和返回值都是类型的一部分,函数可以赋值给一个变量

// test3 函数,接收一个参,参数是函数类型:没有参数没有返回值
// test 有返回值,返回值是个函数:函数有两个参数,一个返回值
//func test3(a func()) func(int, int) int {
// a()
// return func(x, y int) int {
// return x + y
// }
//} // 2 类型重命名 // 可以给类型重命名
// 如果 type Myint int 相当于我们新定义了一个类型,叫Myint
// 如果 type Myint = int 只是重命名,没有新定义类型 type MyFunc func(int, int) int
type Myint = int func test3(a func()) MyFunc {
a()
return func(x, y int) int {
return x + y
}
}
// 我们可以定义自己的类型,简化重复的类型声明 // 3 函数可变长参数
// 可以传任意长度的int类型参数
func test4(a ...int) {
fmt.Println(a) // [1 2 3 4 5] 切片
fmt.Printf("%T", a) // 类型是 int类型切片 []int
} // 4 defer 关键字
func main() { //var a Myint = 9
//var b int = 19
//fmt.Println(a + b)
//fmt.Println(6,3,4,5,5,6,76,7,8)
// 完整定义
//var f MyFunc = test3(func() {
// fmt.Println("被传入的函数")
//})
//res := f(10, 19)
//fmt.Println(res) // 3 可变长参数
//test4(1 2 3 4 5) // 4 defer 延迟调用, 当前函数所有代码都执行完了,再执行defer的内容,先注册,后调用 ,先写的defer后来执行
//var a = 10
//defer func(i int) {
// fmt.Println(i)
// fmt.Println("我很帅")
//
//}(a) defer fmt.Println("我很帅")
defer fmt.Println("我很帅222")
//a = 99
fmt.Println("我不觉得")
fmt.Println("我也不觉得") }

go传入函数:

可见函数类型的完整定义比较麻烦,所以我们可以进行类型重命名,简化代码,这需要使用type关键字:

类型不匹配的情况,需要加等号,让两个类型之间可以计算:

即如果type Myint int 相当于新定义了一个类型,新类型比如Myint是不能和int做运算的。而使用等号的方式只相当于取别名。

println是有返回值的:

可变长参数:

结果a会返回一个切片类型:

defer关键字:

defer的意思是延迟调用。

使用defer:

对函数使用defer:

闭包函数使用defer:

值传递的情况:

闭包函数是多了一种传参的方式,也就是引用传参。

defer会等待当前函数的所有代码都执行完了,再执行defer的内容。

多个defer的执行顺序:

也就是先写的defer一定后来执行。

defer的作用:

defer可以用于文件相关操作(原理f.open 。defer f.close)。go语言没有try..except,go使用defer做异常捕获。

2 包的使用

# python 模块和包
-模块是一个py文件
-包是一个文件夹 有 __init__ # go 包 ---》包是在一个文件夹下,这个文件夹下所有go文件的第一行要声明包
一堆go文件的组合 # 使用步骤
-新建文件夹,写多个go文件,包名必须一致 # 注意点:
'''
// 1 包内部,大写开头,表示导出 变量,函数
// 创建utils,新建文件s1.go
import "fmt"
// 大写表示该函数导出,小写表示隐藏属性
func Add(a,b int)int{
return a+b
}
func test(){
res := Add(4,3)
fmt.Println(res)
}
这个包是执行不了的,需要有main函数。
// 在main包导出
package main
import (
"go_day03/utils"
)
func main(){
// 调用Add
res:= utils.Add(4,5)
fmt.Println(res)
} // 2 包内部的变量函数,只能定义一次
// 新建s2.go
package utils
func Test1(){
// 同一个包下,使用变量和函数
Add()
} // 3 包内部的所有东西,在包内部直接使用
在同一个包内,算作同一个作用域。 // 4 包名可以跟文件夹名不一样,但是一个文件夹下只能有一个包
// 修改utils/s1.go文件
package lqz
// 将 utils --> lqz,这样做就需要将文件夹下的所有文件第一行都改成 package lqz。 // 5 导入包,按路径导入,如果不重命名,就是文件夹必须跟包名一样
// 在别的地方导入,就不能这样使用了
import "go_day03/utils"
func main(){
res:= utils.Add(4,5)
fmt.Println(res)
}
// 这样可以使用
import "go_day03/utils"
func main(){
res:= lqz.Add(4,5)
fmt.Println(res)
}
// 推荐写成
import lqz "go_day03/utils"
func main(){
res:= lqz.Add(4,5)
fmt.Println(res)
}
// 或者将包的名字命名为文件夹的名字,就可以直接导入使用。
// 总结:
// 如果文件夹跟包名不一样,要重命名,可以命名成任意的,但是我们叫了包名
import lqz "go_day03/utils"
// 可以命名成任意的
import qqq "go_day03/utils"
// 以后使用包名. 调用即可 // 6 包内的init函数,可以定义多次,只要导入包,就会依次执行init
init可以写多个,不会报错。
只要导入包,所有的init函数都会执行。
同一目录下按照按照文件名排列顺序执行,比如先执行s1.go, 后执行s2.go.
同一文件内init按照从上往下的顺序,依次执行。 // 7 导入包,必须使用,不使用就报错。现在想导入但是不用,只想执行init
import _ "go_day03/utils" // 8 一个文件夹下可以再建文件夹建新的包,各个文件夹直接没有必然联系,只是文件夹层级关系
在建立新的包。新的go文件:
/utils/lqz/s1.go package lqz
import (
"fmt"
"go_day03/utils"
)
func Add(){
fmt.Println("add")
// 调用utils的add
utils.Add()
} // 9 使用的go mod模式,从1.11后都是这种模式,项目根路径下会有一个go.mod
使用 go get 命令下载第三方包时,Go Modules 会根据 go.mod 文件中记录的依赖关系,从远程仓库下载并存储在 $GOPATH/pkg/mod 目录下。如果已经存在于该目录中,则直接使用已经下载的包。
''' # 之前有个go path模式,已经弃用了,它的包导入,不是从项目路径下开始导入,而是从go path 的src路径下路径下开始导入
go env // 里面会有一个go path
比如我们之前创建的utils包,如果这个包在go path的src目录,我们在项目中就不需要写了,可以直接导入。

3 gin框架使用


# gosdk内置包,自定义包和第三方包
-内置包 fmt\time包
-gin:开一个web服务
-安装第三方包 # 使用gin
配置代理:七牛云
-局部:goland中:GOPROXY=https://goproxy.cn,direct
-全局:改全局go env
安装: go get github.com/gin-gonic/gin 使用fresh启动热部署:
在项目路径下:
go get github.com/pilu/fresh
go install github.com/pilu/fresh@latest
fresh 写代码:
package main
import "github.com/gin-gonic/gin" func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*") // 加载模板文件夹
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"code": "100",
"message": "成功",
})
})
r.GET("/index", func(c *gin.Context) {
c.HTML(200, "index.html", gin.H{"name": "lqz", "age": 19}) // 使用模板,传递变量
})
r.Run() // listen and serve on 0.0.0.0:8080
} // 在index.html文件内使用模板语法
{{.name}} {{.age}}
// 需要注意的是要加上这个点,这跟django模板语法不同。

go中只有模块的概念,没有包的概念。

包名建议叫文件夹的名字,但是可以不是。

函数、变量需要导出才能在外部使用,大写字母开头表示导出。java中就是共有和私有函数。

同一个包内,变量、函数不能重复定义。

同一个包内,使用变量和函数可以直接使用,无需导入。

一个包可能是有多个Go文件写的。

导入包,按照路径导入,如果不重命名,文件夹名必须和包名一致

如果文件夹和包名不一致,需要对包重命名。可以命名成任意的,但是我们叫了包名。

包内的init函数可以定义多次,只要导入包就会依次执行init.

我想导入包但是不使用,只想让包执行init函数;

第三方包:

go语言没有包仓库,大家的代码就放在github上面。

go设置代理:

当前项目局部设置代理:

也可以全局修改:

go env -w GOPROXY=https://goproxy.cn,direct,

gin依赖了一些,go官网的一些模块,不仅仅是去github下载项目,所以需要一些代理,配置七牛云代理,让gin去七牛云下。

4 if-else

// 基本格式
if 条件{ }else if 条件{ }else{ }
// 条件代码块,必须放bool类型
package main

import (
"fmt"
) // if-else func main() {
score := 55
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 && score < 90 {
fmt.Println("良好")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
} }

5 循环

# 不同语言的循环方式
# python
while循环, for循环
# go
for循环
# java
while循环 , for循环 , do while循环
# go的for循环能实现while循环的功能

go的for循环实现while循环的功能:

package main

// 循环

func main() {
// 1 基本语法 for关键字 定义变量i=0;i<10;i++{} 三部分都可以省略,但是一般会保留第二部分,第二部分是条件
//// 2 循环打印0--9
//for i := 0; i < 10; i++ {
// fmt.Println(i)
//}
//fmt.Println(i) // i的作用域范围只在for内部有效 // 3 循环打印0--9 省略掉第一部分 分号不能省
//i := 0
//for ; i < 10; i++ {
// fmt.Println(i)
//}
//fmt.Println(i) // 10 // 4 循环打印0--9 第三部分 分号不能省
//for i := 0; i < 10; {
// fmt.Println(i)
// i++
//} // 5 循环打印0--9 省略第一部分和第三部分 分号能省略
//i := 0
//for i < 10 {
// fmt.Println(i)
// i++
//} // 6 for 条件 {} while 循环
//for true {
// fmt.Println("llll")
//} // 死循环
//for {
// fmt.Println("llll")
//} // 7 上面是基于索引的循环,这个案例是基于迭代的
s := "lqz国中"
//for i, v := range s {
// fmt.Println(i) // 字符串的索引
// fmt.Println(string(v)) // 字符串的值,输出的是该字符在Unicode编码对应的数字,比如汉字‘我’,对应的是25105
//}
// 请注意len获取的是字节长度,lqz占一个字节,每个汉字占三个字节。
//for i := 0; i < len(s); i++ {
// fmt.Println(string(s[i]))
// 汉字要三个字节才能正常解码,这里相当于将汉字的第一个字节拿来解码,依次解码,所以解码不出原汉字,乱码了。
//}
nums := [4]int{25105, 21916, 27426, 20320}
for _, v := range nums {
fmt.Print(string(v))
} // 运行...
} // 8 break和continue: for i := 0; i < 10; i++ {
if i == 5 {
break
}
if i == 2 {
fmt.Println("到达2")
continue
}
}

range是基于迭代的循环:

range循环字符串是按照字符进行循环、如果用len循环字符串是按照字节(有坑)。

6 switch

switch 是一个条件语句,用于将表达式的值与可能匹配的选项列表进行比较,并根据匹配情况执行相应的代码块,优雅的替换掉else-if

package main

import "fmt"

func main() {
// 1 switch 基本使用
//score := 90
//switch score { // 来判断score
//case 90:
// fmt.Println("我是90")
//case 80:
// fmt.Println("我是80")
//case 70:
// fmt.Println("我是70")
//} //// 2 default 的使用
//score := 99
//switch score {
//case 90:
// fmt.Println("我是90")
//case 80:
// fmt.Println("我是80")
//case 70:
// fmt.Println("我是70")
//default:
// fmt.Println("不知道")
//} // 3 多表达式判断
//score := 66
//switch score {
//case 90, 91, 92, 98, 99:
// fmt.Println("我是90")
//case 80, 88:
// fmt.Println("我是80")
//case 70:
// fmt.Println("我是70")
//default:
// fmt.Println("不知道")
//} // 4 无表达式
//score := 66
//switch {
//case score > 90:
// fmt.Println("我是90")
//case score > 80 && score < 90:
// fmt.Println("我是80")
//case score >= 60:
// fmt.Println("大于60")
//default:
// fmt.Println("不知道")
//} //5 Fallthrough 默认情况下,每个条件之间完,默认加break,但是也不用加,其他语言要加,其他语言去掉break,会无条件执行下一个case
// 要无条件执行下一个case,需要使用fallthrough
score := 99
switch {
case score > 90:
fmt.Println("我是90") case score > 80 && score < 90:
fmt.Println("我是80")
fallthrough // 无条件执行下一个case
case score >= 60 && score <= 80:
fmt.Println("大于60")
fallthrough
default:
fmt.Println("不知道")
}
}
只要走到fallthrough,可以无条件执行下一个case。

7 数组

// 定义:
数组是同一类型元素的集合。例如,整数集合 5,8,9,79,76 形成一个数组。
// Go 语言中不允许混合不同类型的元素,例如包含字符串和整数的数组。而python可以。
// 数组是连续存储,存储同一个类型的数据结构
// python 写个单链表 // 定义一个数组:
var a [3]int // 长度为3,int类型
// 使用
a[0] = 99

如下是定义了长度为3,int类型的数组:每个格子,都只能放int类型。不允许存储不同类型元素。

格的大小不一样是不行的,上图这种是错误的。

python的列表,里面放的是地址,地址可以指向任何数据类型,数字,字符串,字典...

深浅拷贝:

Cpython源代码里面有列表字典底层存储。

需要给出类型,不然无法类型推导。

内存溢出,我的应用程序取出别的程序内存存储的东西。

这个数组是直接从内存地址取东西。

go数组一旦定义,大小是不能改变的,类型也不能改变。而列表是可以追加值的,python append会做扩容:

也就是产生新的数组,然后变量指向新的数组。

链表:

数组是连续存储,链表不是连续存储:

链表修改值的时间复杂度是On

数组删除值的时间复杂度是On

如何判断链表有没有环?

也就是链表中间打结。

【Go】函数高级 包的使用 gin框架入门 if-else 循环 switch 数组的更多相关文章

  1. GO语言GIN框架入门

    Gin框架介绍 Gin是一个用Go语言编写的web框架.它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍. 中文文档 Gin框架安装与使用 ...

  2. Go-函数高级使用-条件分支-包管理-for循环-switch语句-数组及切片-与或非逻辑符

    目录 科普 python 注释 # 函数高级 if else if else 包管理 下载第三方包 比较热门的框架 for 循环 for 循环的几种写法 switch 语句 数组及数组切片 数组迭代 ...

  3. 基于gin框架和jwt-go中间件实现小程序用户登陆和token验证

    本文核心内容是利用jwt-go中间件来开发golang webapi用户登陆模块的token下发和验证,小程序登陆功能只是一个切入点,这套逻辑同样适用于其他客户端的登陆处理. 小程序登陆逻辑 小程序的 ...

  4. Gin框架源码解析

    Gin框架源码解析 Gin框架是golang的一个常用的web框架,最近一个项目中需要使用到它,所以对这个框架进行了学习.gin包非常短小精悍,不过主要包含的路由,中间件,日志都有了.我们可以追着代码 ...

  5. gin框架学习手册

    前言 gin框架是go语言的一个框架,框架的github地址是:https://github.com/gin-gonic/gin 转载本文,请标注原文地址:https://www.cnblogs.co ...

  6. Gin 框架 - 安装和路由配置

    目录 概述 Gin 安装 路由配置 推荐阅读 概述 看下 Gin 框架的官方介绍: Gin 是一个用 Go (Golang) 编写的 web 框架. 它是一个类似于 martini 但拥有更好性能的 ...

  7. Gin 框架 - 使用 logrus 进行日志记录

    目录 概述 日志格式 Logrus 使用 推荐阅读 概述 上篇文章分享了 Gin 框架的路由配置,这篇文章分享日志记录. 查了很多资料,Go 的日志记录用的最多的还是 github.com/sirup ...

  8. [系列] Gin框架 - 数据绑定和验证

    目录 概述 推荐阅读 概述 上篇文章分享了 Gin 框架使用 Logrus 进行日志记录,这篇文章分享 Gin 框架的数据绑定与验证. 有读者咨询我一个问题,如何让框架的运行日志不输出控制台? 解决方 ...

  9. 01 . Go框架之Gin框架从入门到熟悉(路由和上传文件)

    Gin框架简介 Gin是使用Go/Golang语言实现的HTTP Web框架, 接口简洁, 性能极高,截止1.4.0版本,包含测试代码,仅14K, 其中测试代码9K, 也就是说测试源码仅5k左右, 具 ...

  10. 在gin框架中使用JWT

    在gin框架中使用JWT JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0业务场景下. 什么 ...

随机推荐

  1. ReverseMe-120

    一道好题,没解出来但是收获很多 贴两位大牛的题解 [精选]攻防世界逆向高手题之ReverseMe-120-CSDN博客 攻防世界ReverseMe-120详解_攻防世界reverseme基本思路-CS ...

  2. python之特殊属性和特殊方法

    目录 特殊属性 __dict__查看属性和方法 __class__查看对象所属类 __bases__查看子类的父类 __mro__查看类的层次结构 __subclasses__查看父类被继承的子类 特 ...

  3. 总结---Django部分(二)

    Django中model的SlugField类型字段有什么用途? SlugField字段是将输入的内容中的空格都替换成'-'之后保存,Slug 是一个新闻术语,通常是某些东西的短标签.一个slug只能 ...

  4. 【Javaweb】jsp | 简单学习【笔记保存】

    什么是jsp,它有什么用? jsp的全称是java server pages.Java的服务器界面. jsp的主要作用是代替Servlet程序回传html页面的数据 因为Servlet程序回传html ...

  5. 深入解析C# List<T>的源码

    前面的文章中解释了Array的初始化和元素插入,以及数组整体的存储结构(<深度分析C#中Array的存储结构>).这里我们再来详细的了解另一种存储结构List<T>, List ...

  6. Android 图表开源库调研及使用示例

    原文地址: Android图表开源库调研及使用示例 - Stars-One的杂货小窝 之前做的几个项目都是需要实现图表统计展示,于是做之前调研了下,做下记录 概述 AAChartCore-Kotlin ...

  7. 【问题解决】unable to do port forwarding: socat not found

    问题复现 前阵子应公司要求做华为云平台的调研,写了一篇文档包含将华为云CCE下载kuberctl配置及使用kubectl转发流量到本地的操作. 今天一早上同事就发来一个错误界面,说是Java远程调试转 ...

  8. 整合SpringBoot + Dubbo + Nacos 出现 Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass

    版本 SpringBoot:2.7.3 Dubbo:3.0.4 Nacos:2.0.3 异常信息如下 Unable to make protected final java.lang.Class ja ...

  9. 记录一下Stream流的一个坑

    List<String> list = new ArrayList<>(); boolean a = list.stream().anyMatch("a": ...

  10. 理解 Paimon changelog producer

    介绍 目的 Chaneglog producer 的主要目的是为了在 Paimon 表上产生流读的 changelog, 所以如果只是批读的表是可以不用设置 Chaneglog producer 的. ...