1.1.1 Go语言的诞生背景
1.1.2 语言特性
1.1.3 Go语言的特性
静态语言,支持运行时动态类型、强类型、支持隐式推导、类型安全、支持type自定义、类型组合支持面向对象、
接口Duck模型、通过接口支持多态、不支持泛型、发射支持、支持垃圾回收、支持协程、支持交叉编译、跨平台
1.2 初识Go程序
hello.go
package main
import "fmt"
func main() {
fmt.Printf("Hello , world\n")
}
go源代码默认UTF-8
区分大小写
{ 不能单独起一行
编译运行
go build hello.go
1.3 Go词法单元
sum := a+b
1.3.1 token
1.3.2 标识符
go变量必须是以字母或者下划线开头。
1.3.3 操作符和分隔符
1.3.4 字面常量
1.4 变量和常量
1.4.1 变量
1.显式的完整声明
var varName dataType [= value] Go的变量声明后会立刻为其分配空间
var a int = 1
var a int = 2*3
var a int = b
2. 短类型声明
varName := value 只能出现在函数内 , 此时Go编译器自动进行数据类型推断。
Go支持多个类型变量同时声明并且赋值,例如: a, b := 1, "hello"
1.4.2 常量
//类似枚举的iota
const (
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
// 简写模式
const (
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
1.5 基本数据类型
Go是一种强类型的静态编译语言
1.5.1 布尔类型
var ok bool
ok = true 或者 ok := false
布尔型数据和整形数据不能进行相互转换
var a bool
a = 1 // error
1.5.2 整形
var a int = (1 + 2) * 3
var b int = 1000 >> 2
1.5.3 浮点型 (float32 和 float64)
var b := 10.00 计算机很难进行浮点数的精确表示和存储,因此两个浮点数之间不应该使用 == 或者 != 进行比较,高精度科学计算应该使用 math 标准库
1.5.4 复数类型
var value1 complex64 = 3.1 +5i
value2 := 3.1 + 6i
Go有三个内置函数处理复数
var v = complex(2.1, 3) // 构造一个复数
a := real(v) // 返回复数实部
b := image(v) // 返回复数虚部
1.5.5 字符串
1. var a = "hello world" 字符串是常量,可以通过类似数组的索引访问其字节单元,但不能修改某个字节的值,例如:
var a = "hello , world"
b := a[0]
a[1] = 'a' // error
2. 字符串转换为切片 []byte(s)要慎重,尤其是当数据量比较大时(每转换一次都需要复制内容)
3. 字符串尾部不包含NULL字符,这一点和C/C++不一样
4.字符串类型底层实现是一个二元的数据结构,一个是指针指向字节数组的起点,另一个是长度,例如:
// runtime/string.go
209 type stringStruce struce {
210 str unsafe.Pointer // 指向底层字节数组的指针
211 len int // 字节数组长度
212 }
1.5.6 rune类型
Go内置两种字符类型:一种是byte,也是uint的别名、另一种表示Unicode编码字符的rune,rune在Go内部是int32类型的别名,占4个字节。
Go默认的字符编码是UTF-8,如果需要转换编特殊的编码,则使用Unicode/UTF-8标准包。
1.6 复合数据类型
Go的复合类型有:指针、数组、切片、字典(map)、通道、结构和接口
1.6.1 指针
1.
var a = 11
p := &a
2.Go不支持指针的运算。
a := 1234
p := &a
p++ // 报错
3. 函数中允许返回全局变量的地址
func sum(a, b int) *int {
sum := a + b
return &sum // 允许,sum会分配在heap上
}
1.6.2 数组
var arr [2]int // 声明一个有两个整型的数组,但元素默认值都是0,一般很少这样使用
array := [...]float64 { 7.0, 8.5, 9.1 } // [...]后面跟字面量初始化列表
数组初始化
a := [3]int {1, 2, 3} //指定长度和初始化字面量
a := [...]int {1, 2, 3} //不指定长度,但是由后面的初始化列表数量来确定其长度
a := [3]int {1:1, 2:3} //指定总长度,并通过索引值进行初始化,没有初始化元素时使用类型默认值
a :=[...]int {1:1, 2:3} //不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元素被初始化为类型的零值。
数组的特点
1、数组创建完长度就固定了,不可以再追加元素
2、数组是值类型,数组赋值或者作为函数参数都是值拷贝。
3、数组长度是数组类型的组成部分, [10]int 和 [20]int 表示不同类型
4、可以根本数组创建切片。
数组相关操作
1、数组元素访问
a := [...]int {1, 2, 3}
b := a[0]
for i, v := range a {
}
2、数组长度
a := [...]int {1, 2, 3}
alength:= len(a)
for i:=0; i< alength; i++ {
}
1.6.3 切片
Go切片 slice 是一种变长数组,其数据结构中有指向数组的指针,是一种引用类型
// src/runtime/slice.go
11 type slice struct {
12 array unsafe.Pointer
13 len int
14 cap int
}
Go切片维护三个元素:指向底层数组的指针、切片元素数量、底层数组容量。
1、切片的创建,创建语法 array[b:e]
var array = [...]int {0, 1, 2, 3, 4, 5, 6} // 创建有76个int型元素的数组
s1 := array[0:4] // [0 1 2 3]
s2 := array[:4] // [0 1 2 3]
s3 := array[2:] // [2 3 4 5 6]
通过内置函数 make 创建切片 (注意:由make创建的切片各元素被默认值初始化为切片元素类型的零值),例如:
a := make([]int, 10) // len = 10, cap = 10 [0 0 0 0 0 0 0 0 0 0]
b := make([]int, 10, 15) // len=10, cap=15 [0 0 0 0 0 0 0 0 0 0]
直接声明切片类型变量是没有意义的,例如:
var a []int
fmt.Printf("%v\n", a) // 结果为 []
2 切片支持的操作
len()
cap() 返回切片底层数据容量
append() 对切片追加元素
copy() 用于复制一个切片
例如:
a := [...]int {0, 1, 2, 3, 4, 5, 6}
b := make([]int, 2, 4) // len(b) = 2 , cap(b) = 4
b = append(b, 1) // len(b)=3 [0 0 1] cap(b) 4
c := a[0:3]
b = append(b, c...) // [0 0 1 0 1 2] len(b) = 6 cap(b)=8//底层数组发生扩展
d := make([]int, 2, 2)
copy(d, c) // copy只会复制d和c中长度最小的 [0, 1] len(d)=2 cap(d)=2
3 字符串和切片相互转换
str := "hello, 世界" //通过字符串字面量初始化一个字符串str
a := []byte(str) //将字符串转换为[]byte类型切片
b := []rune(str) //将字符串转换为[]rune类型切片
1.6.4 map
Go语言内置的字典类型叫做map , 格式为: map[K]T , map也是一种引用类型
1.创建map
使用字面量创建
ma := map[string]int {"a":, "b":2}
fmt.Println(ma["a"])
fmt.Println(ma["b"])
使用内置的make函数创建,例如:
make(map[K]T) // map的容量使用默认值
mp1 := make(map[int]string)
mp1[1] = "tom"
make(ma[K]T, len) // map的容量使用给定的len值
mp2 := make(map[int]string, 10)
mp2[1] = "pony"
2. map支持的操作
可以使用range遍历一个map类型变量 ,但是不保证每次迭代元素的顺序。
可以用len()函数返回map中键值对数量,例如:
mp := make(map[int]string)
mp[1] ="tom"
mp[1] = "pony"
mp[2] = "jaky"
mp[3] = "andes"
删除map中的某个键值,delete(mapName, key)
delete(mp, 3)
for k, v := range mp {
}
注意:
Go内置的map不是并发安全的,并发安全的map可以使用标准包sync中的map
不要直接修改map value内某个元素的值,如果想修改map的某个键值,则必须整体赋值
type User struce {
name string
age int
}
ma := make(map[int]User)
andes := User {
name: "andes",
age: 18,
}
ma[1] = andes
ma[1].age = 19 //报错,不能通过map引用直接修改
andes.age =19
ma[1] = andes //必须整体替换value
1.6.5 struct
Go中的struct类型和C类似,由多个不同类型元素组合而成。
这里有两层含义:1、struct结构中的类型可以是任意类型。2、struct的存储空间是连续的,其字段按照声明时的顺序存放(注意字段之间有对齐要求)
struct有两种形式:一种是struct类型字面量,另一种是使用type声明的自定义struct类型
1、struct类型字面量
struct {
FeildName FeildType
FeildName FeildType
FeildName FeildType
}
2、自定义struct类型
type TypeName strict {
FeildName FeildType
FeildName FeildType
FeildName FeildType
}
3、struct类型变量的初始化
type Person struct {
Name string
Age int
}
type Student struct {
*Person
Number int
}
//按照类型声明顺序,逐个赋值
a := Person { “Tome”, 21} //不推荐这种初始化方式,一旦struct增加字段,则整个初始化语句都会报错
推荐这种使用Feild名字的初始化方式,没有指定的字段则默认初始化为类型的零值
p := &Person {
Name: "tata",
Age: 12,
}
s := Student {
Person: p,
Number: 110,
}
1.7 控制结构
1.7.1 语句
if后面的条件判断子句不需要用小括号括起来
{必须放在行尾,和if或者if else放在一行
if 后面可以带一个简单的初始化语句,并以分好分割,该简单语句声明的变量作用域是整个if语句块,包括后面的else if 和 else 分支
Go语言没有条件运算符 ( a > b ? a : b), 这也符合Go的设计哲学,只提供一种方法做事情。
if 分支语句遇到return后直接返回,遇到break则跳过break下方的if语句块
简单示例:
if x <= y {
return y
} else {
return x
}
一个完整的 if else 语句示例:
if x := f(); x < y { //初始化语句中的声明变量x
return x
} else if x > z { //x在else if 里一样可以被访问
return z
} else {
return y
}
err, file := os.Open("xxxx")
if err != nil {
retutrn nil, err
}
defer file.Close()
1.7.2 switch 语句
switch和if语句一样,switch后面可以带一个简单的初始化语句
通fallthough语句来强制执行下一个case字句(不再判断下一个case子句的条件)
switch i:= "y";i {
case "y", "Y": //多个case值使用逗号分隔
fallthrough
case "n", "N"
}
1.7.3 for语句
for init; condition; post {
}
for可以对数组、切片、字符串、map和通道的访问,例如:
//访问map
for key, value := range map {}
for key := range map {}
//访问数组
for index, value := range array {}
for index := range array{}
for _, value := range array{}
//访问切片
for index, value := range silce {}
for index := range slice{}
for _, value := range slice{}
//访问通道
for value := range channel {}
1.7.4 标签和跳转
goto 、 break、 continue