前文
题记
- 在上一篇文章中,我们介绍了吸心大法—go module的技巧来引用第三方代码,但是看过武侠小说的同学都知道,只有内力没有招式那也是花架子。正所谓"巧妇难为无米之炊",我们将在后面几章巩固基本功,介绍go语言的语法、基本概念和性质。
前言
我们将在本文中学习到:
- 变量的内涵
- 变量的数据类型
- 变量的多种声明与赋值
- 变量的命名
- 变量的作用域与示例
- 变量的内存分配方式
变量是什么
符号名
变量的数据类型
go语言是静态类型的语言,需要在运行前明确变量的数据类型以及大小。如下图是静态语言与动态语言的区别。动态语言可以在运行时扩展变量的大小。
- 数据类型是数据的属性,它告诉编译器打算如何使用数据
- 大多数编程语言都支持基本数据类型,包括整数,浮点数,字符和布尔值等。数据类型定义了可以对数据执行的操作,数据的含义以及该类型值的存储方式
- Go语言的数值类型包括几种不同大小的整数、浮点数和复数。每种数值类型都决定了对应的大小范围和是否支持正负符号。让我们先从整型数类型开始介绍
- Go语言同时提供了有符号和无符号类型的整数运算,有int8、int16、int32和int64四种截然不同大小的有符号整型数类型,分别对应8、16、32、64bit大小的有符号整型数,与此对应的是uint8、uint16、uint32和uint64四种无符号整型数类型。
- 还有两种一般对应特定CPU平台机器字大小的有符号和无符号整数int和uint。其中int是应用最广泛的数值类型。这两种类型都有同样的大小,32或64bit,但是我们不能对此做任何的假设;因为不同的编译器卽使在相同的硬件平台上可能产生不同的大小。
- Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
- 最后,还有一种无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程时才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。在介绍指针时,会详细介绍它。
变量的声明与赋值
var
var name type = expression
- 函数体外部:变量声明方式1
var i int
- 函数体外部:变量声明方式2
// 外部连续声明
var U, V, W float64
- 函数体外部:变量声明方式3
// 赋值不带类型,自动推断
var k = 0
- 函数体外部:变量声明方式4
// 外部连续声明+赋值
var x, y float32 = -1, -2
- 函数体外部:变量声明方式5
// 外部var括号内部
var (
g int
u, v, s = 2.0, 3.0, "bar"
)
- 函数体内部:变量声明方式6
func main() {
//函数内部的变量声明 声明的变量类型必须使用 否则报错
var x string
- 函数体内部:变量声明方式7
// 只限函数内部 自动推断类型
y := "jonson"
变量的命名
- 名字的长度没有逻辑限制,但是Go语言的风格是尽量使用短小的名字,对于局部变量尤其是这样;你会经常看到i之类的短名字,而不是冗长的theLoopIndex命名。通常来说,如果一个名字的作用域比较大,生命周期也比较长,那么用长的名字将会更有意义。
- 在习惯上,Go语言程序员推荐使用 驼峰式 命名,当名字由几个单词组成时优先使用大小写分隔,而不是优先用下划线分隔。因此,在标准库有QuoteRuneToASCII和parseRequestLine这样的函数命名,但是一般不会用quote_rune_to_ASCII和parse_request_line这样的命名。而像ASCII和HTML这样的缩略词则避免使用大小写混合的写法,它们可能被称为htmlEscape、HTMLEscape或escapeHTML,但不会是escapeHtml。
作用域
- 在程序设计中,一段程序代码中所用到的标识符并不总是有效/可用的,作用域就是标识符有效可用的代码范围。
- 在go语言中,作用域可以分为
全局作用域 > 包级别作用域 > 文件级别作用域 > 函数作用域 > 内部作用域
universe block > package block > file block > function block > inner block
全局作用域
- 全局作用域主要是go语言预声明的标识符,所有go文件都可以使用。主要包含了如下的标识符
內建类型: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
內建常量: true false iota nil
內建函數: make len cap new append copy close delete
complex real imag
panic recover
包级别作用域
println
package main
import "fmt"
var x int=5
func main(){
fmt.Println("mainx:",x)
}
- 调用例子1
// f1.go
package main
var x int
//-------------------------------------
// f2.go
package main
func f() {
fmt.Println(x)
}
- 调用例子2:调用另一个包中的函数和属性:
//testdemo/destdemo.go
package testdemo
import "fmt"
var Birth uint = 23
func Haha(){
fmt.Println("lalalal")
}
//-------------------------------------
package main // main/scope.go
import (
"testdemo"
"fmt"
)
func main(){
testdemo.Haha()
fmt.Println(testdemo.Birth)
}
- 注意:如果要让包中的属性和变量被外部包调用,必须要首字母大写。
文件级别作用域
- import包的标识符是文件级别作用域的,只能够在本文件中使用
- 例如下面的代码无效,因为import 是file block,不能跨文件
// f1.go
package main
import "fmt"
//-------------------------------------
// f2.go 无效
package main
func f() {
fmt.Println("Hello World")
}
函数级别作用域
- 方法接收者(后面介绍),函数参数和结果变量的标识符的范围是函数级别作用域,在函数体外部无效,在内部任何位置可见
- 例如下面函数中的a,b,c就是函数级别作用域
func add(a int,b int)(c int) {
fmt.Println("Hello World")
x := 5
fmt.Println(x)
}
内部作用域
- 函数声明的常量和变量是函数内部作用域,其作用域从声明开始,到最近的一个花括号结束。
- 例子1:注意参数的前后顺序
//下面的代码无效:
func main() {
fmt.Println("Hello World")
fmt.Println(x)
x := 5
}
- 例子2:参数不能跨函数使用
//下面的代码无效2:
func main() {
fmt.Println("Hello World")
x := 5
fmt.Println(x)
}
//
func test(){
fmt.Println(x)
}
- 例子3:函数内部变量与外部变量重名,使用就近原则
package main
import "fmt"
var x int=5
func test(){
var x int = 99;
x = 100;
// 下面的代码输出结果为: 100
fmt.Println("testx",x)
}
- 例子4:内部花括号
- 变量x的作用域是从scope3到scope5为止
func main() {
fmt.Println("Hello World") // scope1
{ // scope2
x := 5 // scope3
fmt.Println(x) // scope4
} // scope5
}
变量的内存分配
段
.data.bss
// main.go
package main
var aaa int64 = 8
var ddd int64
func main() {
}
- 在终端中输入如下指令打印汇编代码
$ go tool compile -S main.go
...
"".aaa SNOPTRDATA size=8
0x0000 08 00 00 00 00 00 00 00
"".ddd SNOPTRBSS size=8
...
aaa.dataddd.bss.data长度大于4字符串
func main() {
var vvv = [5]int{1,2,3,4,5}
var bbb string = "hello"
}
.data
$ go tool compile -S main.go
...
go.string."hello" SRODATA dupok size=5
0x0000 68 65 6c 6c 6f hello
type.[5]int SRODATA dupok size=72
"".ddd SNOPTRBSS size=8
...
总结
参考资料
喜欢本文的朋友欢迎点赞分享~
唯识相链启用微信交流群(Go与区块链技术)