简单语法
1. 变量
指定变量类型,如果没有初始化,则变量默认为零值
var 变量名 变量类型
根据值自行判定变量类型。
var 变量名 = 变量值
:= 赋值操作符,声明并且初始化变量,根据值自行判定变量类型
a := 1
等于下面两行语句组合
var a int
a = 1
_空白标识符,是一个只写变量,你不能得到它的值
这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。
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.常量
在变量面前加个const
const 变量名 变量类型 = 变量值
常量枚举
const (
zero = 0
one = 1
two = 2
)
3.数组
数组在声明时,数组中的每个元素都会根据其数据类型进行默认初始化,对于整数类型,初始值为 0。
var 数组名 [size] 数据类型
可以使用 := 简短声明语法来声明和初始化数组:
numbers := [5]int{1, 2, 3, 4, 5}
如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
4.函数
与C++不同,定义函数时,返回值不需要写在开头。
func 函数名( 参数类型 ) 返回值类型 {
函数体
}
5. 切片Slice
Go 数组的长度不可改变,所以Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),长度不固定,可以追加元素但可能使切片的容量增大
声明一个未指定大小的数组来定义切片,切片不需要说明长度,不支持负数索引
var 切片名 []数据变量类型
或
numbers := []int{0,1,2,3,4,5,6,7,8}
或
切片名 := make([]数据类型, 长度, 容量(可选))
方法函数
切片是可索引的,并且可以由len() 方法获取长度。
切片提供了计算容量的方法cap()可以测量切片最长可以达到多少。
空(nil)切片 一个切片在未初始化之前默认为 nil,长度为 0
6.指针(指向值的地址)
声明与定义指针
var 指针名 *指针类型(所指向地址的值的类型)
或
指针名 := &变量
*指针为解引用,返回的是指针指向的内存地址中的变量值
空指针
一个指针被定义后没有分配到任何变量时,它的值为 nil,指代零值或空值
7.结构体
声明与定义 struct 语句定义一个新的数据类型,结构体中有一个或多个成员
type 结构体名 struct {
成员名1 成员1变量类型
成员名2 成员2变量类型
}```
比如视频示例中
```go
type user struct {
name string
password string
}
结构体内部函数 视频示例中定义了函数checkPassword,此处函数接受结构体为外部参数使用。而且函数的参数是浅拷贝,所以想要改变原变量的值需要用指针更改内存地址中的值才可以
func main() {
a := user{name: "wang", password: "1024"}
func checkPassword(u user, password string) bool {
return u.password == password
}
//返回结果为false
这个例子中的checkPassword函数变为了结构体内部的函数,可以使用结构体名.函数 来调用方法
//浅拷贝只是拷贝了值,当函数销毁时一并销毁,是局部变量
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
fmt.Println(a.password) // 2048
}
常用特性
与其他编程语言不同的是,Go 语言的错误处理通过返回值来处理,并且Go 语言内置了对并发编程的支持。
错误处理
error 类型是一个接口类型
定义
函数通常在最后的返回值中返回错误信息。使用 errors.New 可返回一个错误信息
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
并发
Go通过 goroutines 和 channels来实现并发,goroutine 是轻量级线程,而goroutine 的调度是由 Golang 运行时进行管理的。
使用go 语句开启一个新线程
goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。
go 函数名( 参数列表 )
通道(channel)
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。
使用 make 函数创建一个 channel,使用 <- 操作符发送和接收数据。
声明一个通道
ch := make(chan int)
或
ch := make(chan int, 缓冲区(可选))
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态
使用
ch <- v // 把 v 发送到通道 ch
v := <-ch
v, ok := <-ch ,通道接收不到数据后 ok 就为 false
使用 close(ch) 关闭通道
select
select 语句使得一个 goroutine 可以等待多个通信操作。select 会阻塞,直到其中的某个 case 可以继续执行
总结
Go 的语法设计简洁、清晰,语言特性较少,但功能完备,易于理解和学习。学习文档较多,第三方库丰富,开发者可以在短时间内掌握,并快速上手编写高效的代码,并且提供了功能强大的标准库,涵盖网络、文件操作、加密、调试等常见开发场景。并且其生成的二进制程序执行速度接近 C/C++,并具有良好的内存管理机制和垃圾回收功能,适用于性能要求高的场景。 而且go语言并发编程简单化,相比于传统线程模型,Go 的 Goroutine 和 Channel 更加直观,开发者无需直接操作线程,也无需考虑锁机制,大幅降低了并发程序的开发门槛。 最重要的是Go语言社区活跃,第三方库和框架生态丰富,涵盖 Web 开发、微服务、网络通信等领域,为开发者提供了强大的支持