✨✨ 欢迎大家来到景天科技苑✨✨
?? 养成好习惯,先赞后看哦~??
? 作者简介:景天科技苑
?《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
?《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。
所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑
文章目录
Go语言语法注释变量变量的定义短变量的申明方式(语法糖,方便开发人员开发)变量的交换理解变量(内存地址)匿名变量变量的作用域 常量常量的iota枚举器
Go语言语法
注释
我们为什么写注释?
一个项目,是很多组成的。写的时候,你能看懂的。 半年、一年 (时间久了,自己写代码看不懂了)
对接、项目很多时候都是多人协作完成。(很难沟通,直接读懂代码是比较困难)
在刚开始学习的时候,不喜欢写注释。
注释分为单行注释和多行注释
单行注释:双斜线 //
多行注释:/中间是注释/
什么是注释: 来描述我当前这个代码是做什么的,或者一些批注
package mainimport "fmt"// 注释是不会被程序执行的// // 单行注释// 注释主要是针对一些自己不太理解的业务,或者复杂的业务。开源项目中,注释十分完善。/* 多行注释。。。。。。写自己的理解和当前代码作用*/func main() { fmt.Println("Hello,World!")}
以helloworld为例:
// 代表是main包,下面如果存在 main 函数,那么就是程序的入口package main// 导入了一个 fmt 包,可以通过它来调用打印函数、输出一行话....import "fmt"// main函数 func 函数 main 函数的名字 () 没有参数func main() { // 打印了一句helloworld fmt.Println("Hello,World!")}
写注释是一个十分良好的习惯,我们都应该按照要求给自己代码写好注释,为了自己,也为了他人。很多大公司里也是对注释有严格要求的。
变量
变量的定义
程序 : 我们向电脑说了一段话,需要电脑才能理解 (沟通机制 ,xxx语言 – 汇编 – 机器码)
电脑实际上识别的是机器码 : 0 1 1 1 0 1 (高低电频)
机器码 : 穿孔纸带
汇编:早些时候,现在的很多机器硬件底层代码,都是汇编
人能读懂的代码:英文、中文等人类语言
将我们的语言和机器进行对接 (C、Java、Go —> 编译器 --> 计算机中去执行:无需理解的,我们只需要写我们能看懂的代码即可 )
我们理解的世界、和计算机的世界要一一对应:
定义:一切都是需要去定义的。
计算机也需要去定义一些东西。
人名: 名字 name = 景天 字符串。
名字(变量)
name = 张三
name = 李四
计算机也需要这样来认识我们写的代码,也需要一个格式
Go语言中是通过 var 关键字来定义变量
定义变量的时候,需要指定数据类型
变量名字 需要告诉计算机这个信息(变量)是什么类型的,数据类型:数字、字符串、小数… = “变量的值”
//用程序描述一个人的信息// string 字符串类型var name string = "景天"// int 数字类型var age int = 27var sex string = "男"
公式:定义变量 var 变量名 变量类型
同时定义多个变量
var ( addr string phone int)
代码展示:
package mainimport "fmt"func main() { // var 变量名 变量类型 // 定义变量 ,如果没有给这个变量赋值, 就是这个数据类型的默认值。 // string 默认值 ”“ int 默认值 0 var name string var age int // 可以同时定义多个变量,也只需要使用 var() 关键字 var ( addr string phone int ) // goland 快捷键 : 复制当前行到下一行 Ctrl + D fmt.Println("名字是", name) fmt.Println("年龄是", age) fmt.Println("地址是", addr) fmt.Println("手机号码是", phone) // 变量的使用,在定义完毕变量之后直接可以操作这个变量 // 给变量赋值 ,符号 = 赋值(不能叫等于) // 将 "景天" 赋值 给 name 这个变量。 name = "景天" // 使用变量,直接打印或者进行一些操作都可以 fmt.Println(name) // 变量是可以被重复赋值的,变量。 name = "张三" fmt.Println(name) // 在定义变量的时候直接进行赋值。 var dog string = "旺财" fmt.Println(dog)}
短变量的申明方式(语法糖,方便开发人员开发)
只定义变量,不使用可以吗. 理论可以,实际在Go语言中不行。
无意义代码,报错!
go语言中只定义变量,不使用会报错(针对的是局部变量,全局变量定义了不使用不报错)
问题1 :能不能不写数据类型
问题2 :不用var 直接定义变量呢?
自动推导,一个短变量声明
Go语法糖(偷懒,简化开发!)
:= 相当于快递定义变量。如果给这个变量赋值了,那么会自动推导它的类型
var 、 数据类型的定义都被省略的。
自动推导只能推导出go语言中基本的数据类型。
在使用语法糖时,如果变量已经通过var来声明,则不能在通过语法糖自动推导
代码展示
package mainimport "fmt"//短变量func main() { // 只定义变量,不使用可以吗. 理论可以,实际在Go语言中不行。 // 无意义代码,报错! // 问题1 :能不能不写数据类型 // 问题2 :不用var 直接定义变量呢? // 自动推导,一个短变量声明 name := "景天科技" age := 18 // 语法糖(偷懒,简化开发!) // := 相当于快递定义变量。如果给这个变量赋值了,那么会自动推导它的类型 // var 、 数据类型的定义都被省略的。 // 数据类型 go语言中基本的数据类型。 fmt.Println(name) fmt.Println(age) // 定义了变量name2 var name2 string // 在快速声明中,如果 := 左边的变量已经存在了,那么它将无法创建,无法重新定义 //name2 := "景天" name3 := "qinjiang222" fmt.Println(name2) fmt.Println(name3) //语法糖定义的变量,也可以正常被修改的 name3 = "zhangsan666" fmt.Println(name3)}
变量的交换
生活相似案例常见解法
package mainimport "fmt"func main() { /* 在编程中遇到的第一个问题:变量交换 var a int = 100 var b int = 200 var t int t = a a = b b = t */ // 在Go语言中,程序变量交换,也有语法糖 var a int = 100 var b int = 200 // fmt.Println 可以传递多个参数,用逗号隔开,直接打印 fmt.Println("交换前 a=", a, ",b=", b) // 把a,b赋值给b,a 语法糖, 底层本质还是用到了临时变量。简化我们的开发 b, a = a, b fmt.Println("交换后 a=", a, ",b=", b) // 复杂的问题都给我们简单化了,我们开发很轻松,编译器帮我们在底层处理。}
注意:变量交换时,两个变量的数据类型必须一致
理解变量(内存地址)
变量到底是个什么?
num 实际上是一片内存空间
我们想要看一个变量的内存地址,只需要在变量名前加上 & 即可。
取地址符 (指针)
package mainimport "fmt"func main() { // 变量到底是个什么玩意? // num 实际上是一片内存空间 // 我们想要看一个变量的内存地址,只需要在变量名前加上 & 即可。 // 取地址符 (指针) var num int //内存地址在变量声明(创建)的时候就分配 //变量前面加上& 就能打印该变量的内存地址 // %p 内存地址,num需要取出变量的地址。 // 打印内存地址的方式之一。 Print f格式化输出 // 内存 // 第一个参数 输出字符串 // % 占位符。 // 占位符的数量,要和后面待输出的数量一直 // %d 数字 int d // %p 内存地址,num需要取出变量的地址。 // %s 字符串。 // \n 换行 //fmt.Printf("num的值:%d",num) fmt.Printf("num的值:%d,内存地址:%p\n", num, &num) num = 1000 // 思考:这个num在计算机中是什么样子的。 num fmt.Printf("num的值:%d,内存地址:%p\n", num, &num) num = 2000 //值被修改,内存地址没变 fmt.Printf("num的值:%d,内存地址:%p\n", num, &num) // 汇编。理解一切 var name string name = "张三" // 思考:这个num在计算机中是什么样子的。 num fmt.Printf("num的值:%s,内存地址:%p\n", name, &name) name = "李四" fmt.Printf("num的值:%s,内存地址:%p\n", name, &name)}
匿名变量
匿名变量没有名字的变量,十分特殊,可以把一切东西丢进去,任何赋值给匿名变量的值都会被丢弃
go语言中,_ 下划线就是匿名变量。
匿名变量不占用内存空间,不会分配内存。
package mainimport "fmt"// 变量 ( 有名字、没有名字:匿名 )// 十分特殊、匿名变量 (黑洞,一切东西丢进去,任何赋值给匿名变量的值都会被丢弃)// _ 下划线,就是匿名变量在Go语言中// 函数 一段代码的集合。//// func test 函数名 (参数,参数....) 返回一些东西{// 一段代码的集合,通过or不通过参数,返回结果// }//// 基本的操作函数,调用函数,返回两个数字。func test() (int, int) { // return 返回结果 return 100, 200}// 在Go语言中会大量使用到// 匿名变量不占用内存空间,不会分配内存。func main() { // 调用这个test函数,应该会返回两个结果,100,200 // 变量 : 除了直接定义之外,还可以是一个结果的赋值 //var a int = 100 // 只想要test返回的第一个结果,如果我们用其他变量接收,没有使用,也是不行的。这时候就需要使用匿名变量 _。 a, _ := test() // a,b := 100,200 fmt.Println(a) // 只想要test返回的第二个结果,这时候就需要使用匿名变量 _。 _, b := test() fmt.Println(b) //匿名变量不能被使用 //fmt.Println(_)}
变量的作用域
在go语言中,变量分为全局变量和局部变量
全局变量:在当前go文件中生效…
定义在go文件非函数内,在package和import下面
全局变量的定义必须使用 var 关键字, 如果直接使用 := 则无法创建该变量
全局变量和局部变量是可以重名的,优先级(到底用谁) 遵循就近原则
全局变量可以创建了,不使用。不会报错。因为程序执行是执行main函数里面的代码
在Go语言中,变量的作用域指的是变量可以被访问的代码区域。Go语言的变量作用域主要由其声明位置决定,主要可以分为以下几种:
全局作用域:
全局变量是在函数外部声明的变量。这些变量在程序的任何地方(除了函数内部被同名的局部变量遮蔽的情况)都可以被访问。
全局变量的声明周期贯穿整个程序运行期。
函数作用域(也称为局部作用域):
在函数内部声明的变量,仅在该函数内部可见。这些变量被称为局部变量。
函数每次被调用时,其局部变量都会被重新创建。当函数返回时,这些局部变量会被销毁(除非它们被以某种方式返回,例如通过指针或切片等引用类型)。
如果在函数内部再次声明同名变量,则内部声明的变量会遮蔽外部(可能是全局的)同名变量。
块作用域:
Go语言中的块作用域主要体现在if、for、switch等控制结构中。虽然Go语言的规范中没有直接提到“块作用域”这个术语,但控制结构内部的变量声明确实被限制在该控制结构的块内。
这意味着在if、for、switch等控制结构中声明的变量,只能在该结构内部被访问。
包作用域(虽然不是直接由变量声明位置决定,但值得一提):
当你在Go文件的包级别(即不在任何函数内部)声明变量时,这些变量对于同一个包内的所有文件都是可见的,但对于包外的代码是不可见的。这可以视为一种特殊的作用域,因为它与变量声明的位置(包级别)和访问权限(仅限于包内)相关。
代码展示:
package main import "fmt" // 全局变量 var globalVar = "我是全局变量" func main() { fmt.Println(globalVar) // 函数作用域内的局部变量 var localVar = "我是局部变量" fmt.Println(localVar) if true { // 块作用域内的变量,仅在此if块内可见 var blockVar = "我是块作用域变量" fmt.Println(blockVar) // blockVar 在这里可用 } // blockVar 在这里不可用,因为它超出了其作用域 anotherFunction() } func anotherFunction() { // 尝试访问 globalVar,可以成功,因为它在包级别声明 fmt.Println(globalVar) // 尝试访问 localVar 或 blockVar 会失败,因为它们不在当前作用域内 }
实战:
package mainimport "fmt"// 全局变量:在当前go文件中生效...// 定义在go文件非函数内,在package和import下面// 全局变量的定义必须使用 var 关键字, 如果直接使用 := 则无法创建该变量// 全局变量和局部变量是可以重名的,优先级。到底用谁var c intfunc main() { // 局部变量:只在一定的范围内生效... // 在函数体内声明变量 var a int = 3 var b int = 4 // 如果全局变量有,那么直接使用全局变量来接收。 c = a + b fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c) fmt.Printf("c内存地址:%p\n", &c) b = 1 // 但是如果在局部有和全局同名的变量,优先使用局部变量 c := a + b fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c) fmt.Printf("c内存地址:%p\n", &c) b = 5 // 就近原则 c = a + b fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c) fmt.Printf("c内存地址:%p\n", &c) // Printf 格式化输出 (参数一:需要打印的内容,%是占位符,通过后续参数给他一一赋值) fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c)}
就近原则
package mainimport "fmt"// Go语言程序中全局变量与局部变量名称可以相同,但是函数体内的局部变量会被优先考虑。// string int float64 浮点数(小数)//程序的执行顺序是自上而下var a float64 = 3.14func main() { var a float64 = 2.18 fmt.Println(a)}
常量
在Go语言中,常量(Constants)是固定不变的值,它们在编译时被确定,并且在程序的整个生命周期内都不会改变。
常量可以是字符、字符串、布尔值或数值(整数、浮点数等)。常量用于提高代码的可读性和可维护性,特别是在定义那些不应该被改变的值时(如配置参数、物理常量等)。
定义常量
在Go中,你可以使用const关键字来定义常量。常量可以是字符、字符串、布尔值或数值的集合。你还可以在const块中一次性定义多个常量。
两个区别:变量的定义使用 var 、常量的定义是使用const
常量可以定义了不使用,不会报错
是什么机制导致他无法改变的?
Go语言底层的约定,实际上它是可以改变的,需要跳过常量名,直接找到内存地址,进行修改值。
package main import "fmt" const ( // 定义无类型的常量 StatusOK = 200 NotFound = 404 // 字符常量 Pi = 3.14 // 布尔常量 IsEnabled = true // 字符串常量 Name = "Go" ) func main() { fmt.Println(StatusOK) fmt.Println(NotFound) fmt.Println(Pi) fmt.Println(IsEnabled) fmt.Println(Name) }
package mainimport "fmt"// 常量和变量放置的内存地址不同 (栈、堆、常量池)// 程序正常执行,压栈// 常量放在常量池中// 常量func main() { // 规定:建议这么去做 // 我们通过定义常量的时候,建议大家使用大写字母来定义。区分与普通变量 // 一旦定义之后是不会发生变化的。 // 定义格式 const 常量名[type] = value const URL string = "www.jd.com" //Go语言中,由于常量是在编译时期确定的值,常量不会被分配内存地址,所以无法通过取址符 & 来获取常量的地址。 //fmt.Printf("常量URL内存地址:%p\n", &URL) // 隐式定义 常量的自动推导是可以省略一些基础类型, const URL2 = "www.baidu.com" // 可以同时定义多个常量 const URL3, URL4 string = "www.jd.com", "www.baidu.com" // fmt.Println(URL) fmt.Println(URL2) fmt.Println(URL3) fmt.Println(URL4) // 在我们真实的世界也是有很多不会发生变化量,那在程序中对应的就是常量 const PI = 3.14 // 固定的东西,都建议统一定义成常量。 const LENGTH int = 8000 const WIDTH int = 8000 // 常量是无法被修改的。 //LENGTH = 13 fmt.Println(LENGTH)}
常量的iota枚举器
Go语言提供了一个预声明的标识符iota,它是一个在const关键字出现时被重置为0的常量生成器,每当定义一个新的常量时,iota的值就会自动增加1。iota常用于枚举常量。
iota 每次定义新的常量,在一组 const 中,那么它会自动 + 1
如果在定义 const 的时候,如果下面的常量没有赋值,默认沿用上面一个常量定义的赋值。
iota 默认值0
iota一般我们在开发中用于定义错误代码等等
package mainimport "fmt"const ( a = iota // 0 b // 1 c // 2 d = iota // 3, 如果未显式赋值,则iota继续递增 e // 4, iota继续递增 f = 100 // iota不会受f的影响 g // g的值将是上一个被显式赋值的常量的值,即100 h = iota // h的值将重置为iota的当前值,即7(因为iota从上次显式赋值后已经增加了) i)func main() { fmt.Println(a, b, c, d, e, f, g, h, i)}
package mainimport "fmt"// 特殊的常量 iota 常量计数器,const (多个常量,自动帮我们 + 1)func main() { // iota 每次定义新的常量,在一组 const 中,那么它会自动 + 1 // iota 默认值0, const ( a = iota b = iota c = iota d = 0 e = iota // 如果在定义 const 的时候,如果下面的常量没有赋值,默认沿用上面一个常量定义的赋值。 f g h = iota // ... 1000+ ) const ( i = iota // 0 j = 0 // j =0 iota + 1 = 1 //k = iota // iota + 1 = 2 k l m = iota ) // 0 1 2 d=0 ,e = 4 fmt.Println(a, b, c, d, e, f, g, h) fmt.Println(i, j, k, l, m)}
注意事项
常量可以是字符、字符串、布尔或数值的集合。
常量可以是无类型的,但在使用时会根据上下文自动推导为相应的类型。
使用iota枚举器可以方便地定义一组相关的常量。
常量的值在编译时就已确定,并且在程序的整个生命周期内都不会改变。