Z.S.K.'s Records

golang学习(变量)

变量引用

组成一个package的多个文件,编译后实际上和一个文件类似,组成包的不同文件相互之间可以直接引用变量和函数,不论是否导出

go中对于变量(函数也是如此)使用首字母大小写来区别是否可引用. 首字母大写则能被其它包引用(不完全正常, 目前先这么理解).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// cat main.go
package main

import "fmt"

//Aa public var
var Aa int //包变量, 同时对外是public的,初始值跟变量初始值相同, int为0

const (
a = 1 << iota
b
_
d
e
)

func main() {
fmt.Println(Aa) // 0
Aa := 789 //main中的局部变量,注意这里使用了 :=
fmt.Println(Aa) // 789
fmt.Println(a, b, d, e)
mainxx()
}
1
2
3
4
5
6
7
8
9
10
11
// cat other.go
package main

import (
"fmt"
)

func mainxx() {
aa := 123
fmt.Println(aa, Aa)
}

在命令行下运行go run .

输出很正常

1
2
3
4
0
789
1 2 8 16
123 0

变量定义

var

var比较直接, 使用没有限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
)

var aa = 100
func fu() {
var aa = 200
fmt.Println(aa)
}

func main() {
aa := 300
fmt.Println(aa)
}

####:=

:=个人觉得是个比较好的设计, 干练简短, 虽然在开开始学的时候常常会用错

:=用于声明变量并初始化, 且只能用在函数中, 如果你在函数外使用:=会提示

non-declaration statement outside function body

1
2
3
4
5
6
7
func main() {
var xx int
fmt.Println(xx)
xx := 100 // 会提示错误: no new variables on left side of :
// xx = 100
fmt.Println(xx)
}

上面的错误提示,说没有一个新的变量, 原因就在于xx之前已经被定义了, 不能重复定义. 所以这里只能使用赋值

a := 100这句话是声明了变量a, 且给a赋值100

make

1
2
3
4
5
6
// make slice、map和channel,并且返回一个有初始值(非零)的类型
// 声明一个slice
aSlice := make([]string, 10, 20)
// 声明一个map
aMap := make(map[string]string)
// ...

new

1
2
3
4
5
6
7
// new 用于分配了零值填充的T类型的内存空间, 它返回了一个指针,指向新分配的类型T的零值
// 申明一个整体,并返回一个指向整型的指针
aInt := new(int)
fmt.Println(*aInt) // 0
*aInt = 2
fmt.Println(*aInt) // 2
// ...

make跟new是两个用的比较多, 在这里只是简单介绍下, 后面会单独学习它们的区别

常量的定义

const

const跟其它语言的用法一样, 都是声明常量, 常量就是不能被改变的变量(当然通过常量指针还是可以修改的)

const 可以在任何地方使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"fmt"
)

const (
aa = 100 //这里不能使用:=
bb = 200
)

const (
a = 1 << iota
b
_
d
e
)

func main() {
const main_a = 100
main_a = 200 // 如果试图修改const常量会提示: cannot assign to main_a
fmt.Println(aa, bb, a, b, d, e, main_a)
}

iota

iota在const中比较特别, 因此特意提出来说一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const (
mutexLocked = 1 << iota
mutexWoken
mutexStarving
_

// 这是一行注释
mutexWaiterShift = iota
xzy
)

fmt.Println(mutexLocked, mutexWoken, mutexStarving, mutexWaiterShift, xyz)
//输出
1 2 4 4 5

首先,iota是可以参与运算的, iota带表达式的都将应用到下面的常量

比如上面的1<< iota,此时等于0, 整个表达式的值为1

每二行, iota的值等于1了, 1 << 1, 整个表达式的值2

以此类推.

iota在const关键字出现时将被重置为0(const内部的第一行之前),从第一行开始, 每新增一行常量声明(不包括空行及注释)将使iota计数一次(iota可理解为const语句块中的行索引)。使用iota能简化定义,主要用于定义枚举,而且很有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const ( // iota在const内部的第一行之前就被初始化为0
mutexLocked = 0 // iota=0
mutexWoken = 2 // iota=1
mutexStarving = 3 // iota=2
_ // iota=3

// 这是一行注释
mutexWaiterShift = iota // 所以当到这一行时,共增加了5行,索引从0开始,所以iota为4
xyz
)

func main() {
iota := 33 //iota不是关键字, 因此也可以被当成一个普通的变量对待,跟其它变量没有区别
fmt.Println(mutexLocked, mutexWoken, mutexStarving, mutexWaiterShift, xyz)
fmt.Println(iota)
}
//输出
0 2 3 4 5
33

const及iota可参考这里

常见基本类型零值

1
2
3
4
5
6
7
8
9
10
11
12
// 常见的基本类型零值
int 0
int8 0
int32 0
int64 0
uint 0x0
rune 0 //rune的实际类型是 int32
byte 0x0 // byte的实际类型是 uint8
float32 0 //长度为 4 byte
float64 0 //长度为 8 byte
bool false
string ""

有个比较特殊的零值nil, 这个必须要单独说.

问题

如果把一个包分成多个文件,在IDE如vscode中run时,可提示如下错误

最开始的时候一脸茫然, 很明显是因为在ide运行的时候,执行的命令是go run main.go, 只传入了一个main.go,而没有传递others.go, 因此找不到mainxx(), 在命令行下执行也会报同样的错误. 需要运行go run .或者go run *.go,另外, 最好不要形成循环引用, 如果两个文件需要相互引用的话, 引用第三方是个推荐的办法.

参考文章:

转载请注明原作者: 周淑科(https://izsk.me)

 wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?