什么是Go语言
Go性能好,部署简单,学习成本低,逐渐开始流行起来。
Go语言的特性:
1、高并发、高性能:像C++、Java一样高性能;
2、丰富的标准库:无需借助第三方库
3、语法简单,学习曲线平缓:语法类似C语言,但比C语言更加简化,很好上手
4、完善的工具链:编译、代码格式化、包管理、错误检查、补充提示、单元测试等工具
5、静态链接:默认编译结果都默认是静态链接的,可执行文件
6、快速编译:编译速度很快
7、跨平台:交叉编译特性,无需配置交叉编译环境
8、垃圾回收:开发过程无需考虑内存分配
有哪些公司在使用Go语言呢?
基础语法
一、数据类型
1. 常用基本数据类型
-
整型:int、int8、int16、int32、int64、uint(无符号整数)等等
-
浮点型:float32、float64
-
布尔类型:bool,值为true或false
-
字符串类型:string
(go语言中,字符串是内置类型,可以直接使用加号拼接,也可以直接使用等于号去比较两个字符串)
2. 常用复合数据类型
-
数组 (
[n]T
):固定长度的元素集合,类型为T
,长度为n
-
切片 (
[]T
):动态大小的数组,可以随时增删元素 -
映射 (
map[K]V
):键值对的集合,K
为键的类型,V
为值的类型 -
结构体 (
struct
):一组字段的集合,可以定义自定义数据结构 -
指针 (
*T
):存储另一个变量的内存地址
3. 引用类型
-
接口 (
interface
):定义了一个或多个方法签名的集合 -
通道 (
chan T
):用于 Goroutine 之间的通信
4. 函数类型
- 函数类型可以作为变量类型或参数类型,用于传递函数
二、变量
go是强类型语言,每个变量都有自己的变量类型,而且在go中大部分运算符的使用和优先级都和C和C++类似
变量声明方式有两种:
-
第一种
var a = "hello"
(不显示指出变量类型,程序自动推断)
var b, c int = 1,2
(也可以自行写出变量类型,变量类型写在变量名之后) -
第二种
f := float32(e)
(变量名 := 值)
常量:使用const定义,在go中的常量没有确定的类型,会根据使用的上下文来自动确认类型
三、if-else语句
if后面没有(),但if后必须要有{}
基本结构
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 if odd")
}
四、循环语句
Go中只有for循环,与C++、Java语法类似,只是去除了条件语句的()
基本结构
for i := 0; i < 10; i++ {
fmt.Println(i)
}
五、 switch
go中的switch语句,不需要显示加break语句,switch
会自动在每个 case
执行完后终止,不会自动继续执行后续的 case
。这意味着每个 case
块都是独立的,只有匹配的 case
会被执行。
基本结构
a := 2
switch a {
case 1:
fmt.Println("a is 1")
case 2:
fmt.Println("a is 2")
case 3:
fmt.Println("a is 3")
default:
fmt.Println("a is not 1,2,3")
}
//输出a is 2
六、数组
数组 ([n]T
):具有编号且长度固定的元素序列,与其他编程语言类似
//定义a为数组类型,长度为5
var a [5]int
//访问a[4]元素,并赋值
a[4] = 100
//另一种定义方式,长度为5,元素为1,2,3,4,5
b := [5]int{1,2,3,4,5}
数组遍历
arr := [5]int{1,2,3,4,5}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i]) // 输出每个元素
}
for index, value := range arr {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
七、切片
切片slice ([]T
):不同于数组,可以任意更改长度,也有很丰富的操作。
1. 创建
使用make创建(创建初始长度为3,类型为string的切片)
s := make([]string,3)
2. 赋值
可以像数组一样访问内部的值进行赋值
s[0] = "a"
s[1] = "b"
s[2] = "c"
3. 添加元素
使用append来追加元素(注意append会定义的初始长度后添加元素)
s = append(s,"d")
4. 访问
slice拥有像python一样的切片操作(左闭右开原则)
//s = [a,b,c,d]
fmt.Println(s[1:3])//[b c]
fmt.Println(s[:4])//[a b c d]
fmt.Println(s[1:])//[b c d]
八、map
映射 (map[K]V
):是实际使用过程中最频繁用到的数据结构,golang的map是完全无序的,遍历时也不会按照字母顺序排序,而是随机排序
map
是一种内置的数据结构,用于存储键值对(key-value pairs),它具有高效的查找、插入和删除操作。map
的实现基于哈希表,因此它的操作复杂度平均为 O(1)。
1. 创建map
使用 make
函数可以创建一个空的 map
,需要指定键和值的类型。
//map[key]value,创建一个空的 map,键为 string 类型,值为 int 类型
m := make(map[string]int)
2. 存储键值对
可以通过简单的赋值语法将键值对存储到 map
中。
m["one"] = 1
m["two"] = 2
fmt.Println(m)//map[one:1 two:2]
3. 获取map长度和值
fmt.Println(len(m))// 2
fmt.Println(m["one"])// 1
4.删除键值对
//map的删除
delete(m, "one")
fmt.Println(m)//map[two:2]
5.查询键是否存在
//map的查找
v, ok := m["two"]
fmt.Println(v, ok)// 2 true
r, ok := m["three"]
fmt.Println(r, ok)// 0 false
九、range
对于slice或者map来说,可以使用range来快速遍历,这样可以使代码更加简洁。
range遍历时会返回两个值,第一个索引,第二个是对应位置的值。如果不需要索引可以使用下划线来忽略
// 遍历 slice
slice s := []string{"apple", "banana", "cherry"}
fmt.Println("Slice:")
for i, v := range s {
fmt.Printf("Index: %d, Value: %s\n", i, v)
}
// 遍历 map
map m := map[string]int{
"apple": 5,
"banana": 10,
"cherry": 15,
}
fmt.Println("\nMap:")
for k, v := range m {
fmt.Printf("Key: %s, Value: %d\n", k, v)
}
十、函数
这个是 Golang 里面一个简单的实现两个变量相加的函数。 Golang 和其他很多语言不一样的是,变量类型是后置的。
Golang 里面的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值是一个错误信息。
基本结构
func functionName(parameters) returnType {
// 函数体
}
示例
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
func main() {
res := add(1, 2)
fmt.Println(res)
v, ok := exists(map[string]string{"a": "A", "b": "B"}, "c")
fmt.Println(v, ok) //v返回空字符串,ok为false
}
十一、指针
在 Go 语言中,指针(Pointer)是用于存储变量地址的特殊类型,提供了直接操作内存的能力。与一些其他语言不同,Go 中不支持指针算术(如 p++
等),主要用途就是对于传入参数进行修改,因此指针的使用相对安全且简单。
1. 指针的声明和使用
- 使用
*
符号声明指针类型。例如,*int
表示一个指向int
类型的指针。 - 使用
&
符号获取变量的地址,从而创建指针。 - 通过
*
操作符来解引用指针,即访问指针指向的值。
func main() {
var x int = 10
var p *int = &x // p 是指向 x 的指针
fmt.Println("x 的值:", x) // 输出 10
fmt.Println("x 的地址:", &x) // 输出 x 的内存地址
fmt.Println("p 的值:", p) // 输出 x 的地址
fmt.Println("p 指向的值:", *p) // 输出 10,即 x 的值
// 修改指针指向的值
*p = 20
fmt.Println("x 的新值:", x) // 输出 20
}
2. 指针的零值
- 指针的零值是
nil
,表示指针不指向任何有效的内存地址。 - 使用指针前一般检查是否为
nil
,避免运行时错误。
var p *int // p 是一个 nil 指针
if p == nil {
fmt.Println("p 是一个 nil 指针")
}
3. 在函数中使用指针
在 Go 中,函数参数是按值传递的,即传递的是副本。如果想要在函数内修改原始变量的值,可以传递指针。
//无效,n是形参
func add2(n int) {
n += 2
}
//
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add2(n)
fmt.Println(n)//5
add2ptr(&n)
fmt.Println(n)//7
}
4. 指针和结构体
结构体常使用指针传递,以避免复制大块数据。可以通过结构体指针直接访问字段。
5. new 和 make 的区别
new
:分配内存并返回指向该类型零值的指针。例如,new(int)
返回*int
,值为0
。make
:用于初始化 slice、map 和 channel 等引用类型,返回的是类型本身而不是指针。
6. Go 中的指针和安全性
- Go 中没有指针算术运算(如
p++
),这减少了指针使用的复杂性和出错几率。 - 垃圾回收机制确保不再使用的内存会自动释放,不需要手动管理内存.
十二、结构体
结构体是带类型的字段的集合
1. 定义结构体
Go 语言使用 type
关键字定义结构体。结构体由字段(字段名和字段类型)组成,每个字段都有自己特定的数据类型。
type Person struct {
Name string
Age int
Address string
}
上述代码定义了一个 Person
结构体,包含 Name
、Age
和 Address
三个字段。
2. 结构体的实例化
结构体的实例化可以通过字面量、new
关键字或 &
操作符来完成。
// 1. 使用字面量
p1 := Person{Name: "Alice", Age: 30, Address: "123 Street"}
// 2. 使用 new 返回指针
p2 := new(Person) // p2 是 *Person 类型
p2.Name = "Bob"
p2.Age = 25
// 3. 使用 & 操作符返回指针
p3 := &Person{Name: "Charlie", Age: 35}
3. 访问和修改字段
使用点号 .
可以访问结构体的字段,并对字段进行读取和修改。
go
复制代码
fmt.Println(p1.Name) // 输出 "Alice"
p1.Age = 31 // 修改字段值
fmt.Println(p1.Age) // 输出 31
4. 结构体方法
Go 支持为结构体定义方法。方法的定义类似于普通函数,但需要指定接收者(receiver)。
type Person struct {
Name string
Age int
}
// 为 Person 结构体定义一个方法
func (p Person) Greet() {
fmt.Println("Hello, my name is", p.Name)
}
- 在方法定义中,
p Person
表示接收者p
是Person
类型的实例。 - 可以使用值接收者或指针接收者。值接收者不会改变原始数据,而指针接收者可以修改原结构体的字段。
5. 值接收者和指针接收者
- 值接收者:方法的接收者是结构体的一个副本,方法内部的修改不会影响原结构体。
- 指针接收者:方法的接收者是结构体的指针,方法内部可以直接修改原结构体的字段。
// 使用指针接收者
func (p *Person) UpdateAge(newAge int) {
p.Age = newAge
}
6. 嵌套结构体和组合
Go 中不支持继承,但可以通过将一个结构体嵌入到另一个结构体来实现组合,这种方式可以让结构体之间共享字段或方法。
type Address struct {
City string
State string
}
type Person struct {
Name string
Age int
Address // 匿名嵌套
}
通过这种嵌套方式,Person
可以直接访问 Address
的字段:
p := Person{Name: "Alice", Age: 30, Address: Address{City: "New York", State: "NY"}}
fmt.Println(p.City) // 输出 "New York"
7. 零值初始化
Go 中的结构体会自动初始化为零值。例如,字符串字段的默认值是空字符串 ""
,整型字段的默认值是 0
。
var p Person // p 是一个零值的 Person 实例
fmt.Println(p.Name) // 输出 ""(空字符串)
fmt.Println(p.Age) // 输出 0
8. 标签(Tags)
Go 的结构体字段支持标签,通常用于 JSON 序列化、数据库映射等场景。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
标签 json:"name"
表示 Name
字段在 JSON 中的键名为 "name"
。