这是我参与【第五届青训营】伴学笔记创作的第1天
作为一个刚接触go语言的小白,刚学习王克纯老师的第一节课,内心只有一个感受:哇!这就是高手吗?放在大学要讲十几个课时的内容,大佬竟然只需要半个小时就讲完了!虽然王克纯老师讲的很好,课上老师讲的东西都理解了,但是课下再回想的时候,还是有点生疏,所以,废话不多说,复习来一波。进入今天的笔记复习内容。(课上教授内容较多,为了更好的学习与复习,课上讲授的内容将分为数篇来记录)
一、Go语言的基础结构
与Go的初次相遇是很美好的,它向我热情地打着招呼:“Hello World!”。
package main
import "fmt"
func main() {
var arr = "Hello World!"
/*这是我的第一个简单的程序*/
fmt.Println(arr)
}
它的基础组成有这么几个部分:
- 包声明
第一行代码 package main 定义了包名。我们必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
- 引入包
第二行 import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
- 函数
第三行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
- 变量
第四行的var arr是声明一个名字为arr的变量并为其赋值为“Hello World!”。Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。声明变量的一般形式是使用 var 关键字,并且一般会对其进行赋值操作。
- 注释
第五行 /.../ 是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
- 语句 & 表达式
第六行 fmt.Println(...) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
注: 标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(AZ和a-z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
以下是有效的标识符:
myname abc my_name a_123 Myname myname50 _temp j a23b9 retVal以下是无效的标识符:
- 123ab(以数字开头)
- case(Go 语言的关键字)
- a+b(运算符是不允许的)
二、Go的数据类型
在 Go 编程语言中,数据类型用于声明函数和变量。
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。
| 类型 | 描述 |
|---|---|
| 布尔型 | 布尔型的值只能是常量 true 或者 false。 |
| 数字类型 | 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。 |
| 字符串类型 | 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。 |
| 派生类型 | (a) 指针类型(Pointer)(b) 数组类型(c) 结构化类型(struct) (d) Channel 类型(e) 函数类型 (f) 切片类型 (g) 接口类型(interface)(h) Map 类型 |
三、Go的语言变量
3.1单变量声明
3.1.1 指定变量类型
如果没有初始化,则变量默认为零值,零值是系统默认设置的值
实例展示:
package main
import "fmt"
func main() {
// 声明一个变量并初始化
var a string = "Hello World!"
fmt.Println(a)
// 没有初始化就为零值
var b int
fmt.Println(b)
// bool 零值为 false
var c bool
fmt.Println(c)
}
输出结果:
Hello World!
0
false
- 数值类型的零值为 0
- 布尔类型的零值为 false
- 字符串的零值为 "" (空字符串)
3.1.2 根据值自行判定变量类型
实例展示:
package main
import "fmt"
func main() {
var a = "Hello World!"
fmt.Println(a)
}
输出结果: Hello World!
3.1.3 使用 := 声明变量
实例展示:
package main
import "fmt"
func main() {
a := "Hello World!"
fmt.Println(a)
}
输出结果: Hello World!
- 使用:=是声明变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值
- 如果变量已经使用 var 声明过了,再使用 := 声明变量,就产生编译错误
示例:
package main
import "fmt"
func main() {
var a string
a := "Hello World!"
fmt.Println(a)
}
上面的代码会提示No new variables on the left side of ':=,即定义了同一个变量,产生冲突
3.2 多变量声明
实例展示:
package main
import "fmt"
func main() {
//声明类型相同的多个变量, 适用于局部变量
var a, b, c int //声明变量类型
a, b, c = 1, 2, 3
fmt.Println(a, b, c)
var d, e, f = 4, 5, 6 // 不声明变量类型,自动推断
fmt.Println(d, e, f)
// 这种因式分解关键字的写法一般用于声明全局变量
var (
g bool
h int
)
fmt.Println(g, h)
}
输出结果:
1 2 3
4 5 6
false 0
四、 Go的语言常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义格式(一般可以省略type,因为编译器会自动推断常量类型):
const name [type] = value
多个相同类型的声明可以简写为:
const a, b = value1, value2
实例展示:
package main
import "fmt"
func main() {
const LENGTH int = 10
const WIDTH int = 5
var area int
area = LENGTH * WIDTH
fmt.Printf("矩形的面积为 : %d", area)
}
输出结果:
矩形的面积为 : 50
五、理解拓展
5.1 值类型与引用类型
int、float、bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值:
图5.1.1
使用赋值符 = 将一个变量的值赋值给另一个变量时,如:j = i,实际上是在内存中将 i 的值进行了拷贝:
图5.1.2
我们可以通过 &i 来获取变量 i 的内存地址,例如:0xf840000040(每次的地址都可能不一样)。值类型变量的值存储在堆中。
一个引用类型的变量 r1 存储的是 r1 的值所在的内存地址(数字),或内存地址中第一个字所在的位置。
图5.1.3
这个内存地址称之为指针,这个指针实际上也被存在另外的某一个值中。 同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。当使用赋值语句 r2 = r1 时,只有引用(地址)被复制。
如果 r1 的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2 也会受到影响。
5.2 变量拓展
在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的,编译器会提示错误 no new variables on left side of :=,但是 a = 20 是可以的,因为这是给相同的变量**赋予一个新的值。
如果在定义变量 a 之前使用它,则会得到编译错误 undefined: a。
如果声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误 a declared but not used。
空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。 _ 实际上是一个只写变量,不能得到它的值。这样做是因为 Go 语言中必须使用所有被声明的变量,但有时并不需要使用从一个函数得到的所有返回值。
实例展示:
package main
import "fmt"
func main() {
_, numb, strs := numbers() //只获取函数返回值的后两个
fmt.Println(numb, strs)
}
//一个可以返回多个值的函数
func numbers() (int, int, string) {
a, b, c := 1, 2, "str"
return a, b, c
}
输出结果: 2 str
5.3 常量拓展
- 常量还可以用作枚举,如果定义常量组时,如果不提供初始值,则表示将使用上行的表达式。
实例展示:
package main
import "fmt"
const (
a = 1
b
c
)
func main() {
fmt.Println(a, b, c)
}
输出结果: 1 1 1 iota,特殊常量,可以认为是一个可以被编译器修改的常量。
- iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。 iota 也可以被用作枚举值。
实例展示:
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "Hello" //iota += 1
e // iota += 1
f = 100 //iota +=1
g // iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a, b, c, d, e, f, g, h, i)
}
输出结果: 0 1 2 Hello Hello 100 100 7 8
**笔者有话说:虽然刚开始接触一门全新的语言,一切都是那么的陌生,但是只要我们不断的学习和复习,不断的总结,不断的实践,相信,掌握很快就会这门语言!