变量内存常量
教程地址:点击去往视频教程
1. 变量赋值
var 变量名 变量类型
是变量的声明语法,其值为对应变量类型的默认值。
默认值:
- 整型:0
- 浮点型:0.0
- 布尔:false
- 字符串:空字符串
- 指针型:nil
如果想要给变量赋值,格式为:var 变量名 变量类型 = 值
func main() {
var a string = "mszlu"
}
1
2
3
2
3
Go是一门号称简洁
的语言,简洁性体现在代码上,就是不需要写的代码,可以不用写。
var a string = "mszlu"
这行代码,string这个类型是可以不用写的,Go会自动推导其类型。
func main() {
var a = "mszlu"
}
1
2
3
2
3
同时你会发现,每次写var
也挺麻烦,所以Go提供了更为简洁的写法:a := "mszlu"
只不过简短格式有一些限制:
- 只能用在函数内部
package main
import "fmt"
// a := "mszlu" 不能再函数外部书写
func main() {
a := "mszlu"
fmt.Printf("%s", a)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
如果需要定义多个变量,但是每行都使用var
比较繁琐,可以使用批量定义方式:
var (
a int
b string
c []float32
)
1
2
3
4
5
2
3
4
5
2. 内存初识
变量一旦声明后,就会在内存中占用一部分空间,大家可能会想,内存是不是会很乱呢?
Golang提供了一套内存管理机制,通过对内存的有效管理来提升性能。
经典的进程视角内存布局:
- bss和data两部分存放
全局变量
和静态变量
- text存放代码
- stack栈区存放
局部变量
和函数参数
(用于静态内存分配
),后进先出
的数据结构- 栈区的数据大小在
编译时就是已知的
- 每一个线程都有一个栈区,不共享
- 栈区的数据大小在
- heap堆区用于
动态内存分配
,指针,数组,大数据通常存储在堆区- 所有线程共享堆,是go做内存管理的主要区域
Golang中有一个语言特色的go协程(goroutine),是不同于线程的,但是类似于线程,所以也有单独的
栈
,但是goroutine的栈大小不固定,初始为2kb
,动态增减。
所以go管理内存主要有两块区域:
动态分配的全局堆
goroutine的本地堆栈
Golang喜欢在
栈区分配对象
,这便于垃圾回收,这是区别于很多编程语言的一点
3. 常量
如果我们定义一个了变量,并且初始化了一个值,这个值在程序运行期间,永远不会变化,这时候我们应该将其定义为常量
。
- 避免魔法值
- 常量可以执行编译期优化
例子:
package main
import "fmt"
const PI float64 = 3.1415926
func main() {
fmt.Println(PI)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
常量只能定义布尔型,整型,浮点型和底层类型为这些类型的(比如byte,rune)
3.1 iota
在golang中并没有枚举这种类型,但在go中有类似的方式,就是使用iota
常量生成器。
- 从定义开始,iota值从0加1
例子:
const (
January Month = 1 + iota
February
March
April
May
June
July
August
September
October
November
December
)
func main() {
fmt.Println(December)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
奇数定义:
//go中值部分 可以写表达式
const (
Odd1 = 2*iota + 1
Odd2
Odd3
)
1
2
3
4
5
6
2
3
4
5
6
问题:
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday = iota
)
//Saturday值是多少
func main() {
fmt.Println(Saturday)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
4. 作用域
变量有其生效的区域,这个区域,我们称之为作用域
。
- 函数内部声明的变量,为
局部变量
,作用域仅限于函数内部 - 函数外部声明的变量,为
全局变量
,作用域在当前包有效,如果首字母大写,在所有包有效 {}
包括的区域,称之为代码块,如果变量定义在{}
内部,只在代码块内有效
例子:
func main() {
//只在main函数内有效
getValue()
//不能使用 i只在getValue函数内有效
fmt.Println(i)
}
func getValue() {
var i = 10
fmt.Println(i)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
var i = 10
func main() {
//能使用
getValue()
//能使用
fmt.Println(i)
}
func getValue() {
fmt.Println(i)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
func main() {
{
var i = 10
fmt.Println(i)
}
//不能使用
fmt.Println(i)
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8