需要养成一个好习惯: 代码中配上适当的注释说明 -> 方便人家阅读源码, 也有利于自己对于代码的逻辑以及业务的梳理和理解 💪
// 当行注释
/*
* 多行注释
*/
变量
程序: 人类编写的, 需要电脑理解操作的东西 最终是需要编译 汇编 -> 机器码(0和1) (这是机器唯一能够直接执行~)
变量: 可以理解为是一块内存的标识 其本身有自己的'名字' 就是内存地址 (以十六进制表示 如 0x123344)
(变量的实质为内存空间)
变量的含义
package main
import "main"
func main(){
// 可以通过 fmt.Printf 来格式化输出 内存的地址
var num int = 20
// % 为占位符 与后面带输出的变量数量保持一致
fmt.Printf("num的值为:%d\n",num) // num的值为20
fmt.Printf("num指向的内存空间为:%p\n",&num) // %p 为输出内存地址, 这里需要用取地址符 (&)
// num指向的内存空间为:0xc0000a6058
}
变量的定义
通过关键字var 定义变量 若没有赋值, 则打印的是该数据类型的默认值
package main
import "main"
func main(){
// var 变量名 变量的数据类型
// 定义变量的时候, 若没有给这个变量赋值, 则打印出来的是该数据类型的默认值
// 定义变量的时候可以直接赋值(初始化), 或者也可以 定义变量 和 赋初值(用'='赋值) 分开写
var name string
var age int // string 默认值 "" int 默认值 0
// 可以同时定义多个变量 用小括号包裹
var (
name1 string
age1 int
)
// := 自动推导, 短变量声明, 如果给这个变量赋值了, 那么会自动推导它的数据类型(基本数据类型)
// 只能用于变量
// 在快速声明中, 若 := 左边的变量已经存在, 那么它将无法创建 (只能用新变量, 不能先定义)
name := "sam" // 相当于 var name string name="sam"
}
变量的交换
思路是 用第三个变量作为中间变量
package main
import "fmt"
func main() {
// 交换两个变量 常用思路 引入一个中间(临时)变量
var t int
t = a
a = b
b = t
// 在 Go 中有对应的语法糖 加持 (其实是编译器帮我们实现了上面的逻辑, 方便我们开发)
var a int = 1
var b int = 2
fmt.Println("交换前 a=", a, "b=", b) // 这个是自带换行输出效果
a, b = b, a // 完成a,b 两个数字交换
fmt.Println("交换后 a=", a, "b=", b)
// 交换前 a= 1 b= 2
// 交换后 a= 2 b= 1
}
匿名变量
_
可以接受任何值 匿名变量 不会占用内存空间, 也不会分配内存
一般用于接收函数返回值, 可能只想要其中的一部分返回值, 这时候其他变量就需要用匿名变量 _
来接收
全局变量 & 局部变量
Go 中若出现全局变量与局部变量的变量名重名的情况, 那么会优先考虑局部变量 (就近原则)
package main
import "fmt"
// 全局变量: 在当前go文件中生效
// 定义在 .go 文件的非函数内 (package, import 下面)
// 全局变量的定义 必须使用 var 关键字
// 全局变量 可以定义了 不用, 但是局部变量(函数体内定义) 就不行, 因为程序执行的是函数体内
var c int
func main() {
// 局部变量: 只在一定的范围内生效..
// 在函数体内声明变量
// 局部和全局变量可以重名, 有全局变量用全局变量。若有重名, 则会优先用局部变量 (就近原则)
fmt.Printf("变量c的内存地址%p\n", &c) // 变量c的内存地址0xaf9408
c = a + b // 这里用的是全局变量
fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c) // a=1,b=2,c=3
fmt.Printf("变量c的内存地址%p\n", &c) // 变量c的内存地址0xaf9408
// 可以看出这里使用全局变量 后面的使用局部变量
b = 3
c := a + b // 这里是创建了个名为c的局部变量 故此后使用的是局部变量
fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c) // a=1,b=3,c=4
fmt.Printf("变量c的内存地址%p\n", &c) // 变量c的内存地址0xc0000200e0
b = 5
c = a + b // 1+5
fmt.Printf("a=%d,b=%d,c=%d\n", a, b, c) // a=1,b=5,c=6
fmt.Printf("变量c的内存地址%p\n", &c) // 变量c的内存地址0xc0000200e0
}
常量
常量是不能变化的量, 是一个特殊的变量. 用关键字 const 修饰
Go语言底层的约定, 实际上可以修改。若想改, 则需要跳过常量名, 直接找到其内存的地址, 来修改其值
常量定义了 可以不使用 (这样并不会爆错, 但是普通常量就不可以了, 因为其存放的地方不一样)
package main
import "fmt"
func main() {
// 建议这么做 建议用大写字母来定义 用以区分普通变量
// 一旦定义了 不会发生变化 (! 不能用短变量声明的方式 := )
// 定义格式: 显式定义 const 常量名 [type] = value
const URL string = "www.baidu.com"
// 隐式定义 常量的自动推导 可以省略一些基本类型 (当然可以定义多个常量)
const U1,U2,U3 = "1","2","3"
}
特殊常量iota
可以理解为常量计数器, 当有多个常量的时候, 帮助我们计数
package main
func main() {
const (
a = iota // iota 默认值为0 在一组const中, 当每次定义新的常量, 其会自动 + 1
b = iota
c = iota
)
fmt.Println(a,b,c) // 0 1 2
const (
aa = iota
bb = iota
cc = iota
d = 0 // iota计的是在一组const 里面 定义了多少个常量~
e = iota
// 若常量没有赋值, 会默认沿用上一个变量定义的赋值~
f = 0
g
h = iota
)
const (
i = iota // 新的一组const iota 默认为0 iota = 0
j = 0 // j = 0 iota + 1 = 1
k = iota // iota + 1 = 2
)
fmt.Println(aa, bb, cc, d, e, f, h, h) // 0 1 2 4 0 0 7
fmt.Println(i,j,k) // 0 0 2
}
内存地址存放
常量和变量存放的内存区域会有不同 (有 栈, 堆, 常量池) 详情见之后的笔记~