Go介绍
什么是Go?
- Go是一种跨平台的开源编程语言
- Go可用于创建高性能应用程序
- Go是一种快速、静态类型、编译语言,具有动态类型、解释语言的感觉
- Go的语法类似于C++
Go的应用场景
- 服务端Web开发
- 开发基于网络的程序
- 开发跨平台企业应用程序
- 云原生开发
Go的特性
- 快速的运行时和编译时间
- 支持并发
- 具有内存管理功能
- 可以在不同平台上运行(Windows、Mac、Linux、Raspberry Pi等)
Go语言结构
一个Go文件的主要组成部分:
- 包声明
- 包导入声明
- 函数
- 变量
- 语句和表达式
下面是一段简单的Go代码:
package main
import ("fmt")
func main() {
fmt.Println("Hello World!")
}
package main 表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )
执行Go程序
运行 hello.go 文件中的代码:
$ go run hello.go
Hello World!
编译 hello.go 为二进制文件:
$ go build hello.go
$ ls
hello hello.go
$ ./hello
Hello World!
Go的数据类型
Go语言提供了多种数据类型,包括以下几种常见类型:
基本数据类型
- bool:布尔类型,取值为true或false。
- int、int8、int16、int32、int64:整数类型,分别表示不同位数的有符号整数。
- uint、uint8、uint16、uint32、uint64:无符号整数类型,分别表示不同位数的无符号整数。
- float32、float64:浮点数类型,分别表示32位和64位浮点数。
- complex64、complex128:复数类型,分别表示32位和64位复数。
- byte:类似于uint8的别名,表示一个字节。
- rune:类似于int32的别名,表示一个Unicode码点。
字符串类型
字符串就是一串固定长度的字符连接起来的不可变序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
复合类型
- 数组(Array):由固定长度的相同类型元素组成的数据结构。
- 切片(Slice):动态长度的可变序列,基于数组实现。
- 结构体(Struct):由多个字段组成的复合数据类型,每个字段可以是不同类型。
- 映射(Map):无序的键值对集合。
- 通道(Channel):用于协程之间的通信和同步。
其他类型
- 接口(Interface):定义了一组方法签名,用于实现多态。
- 函数(Function):可独立执行的代码块,也可作为值传递。
- 指针(Pointer):存储变量内存地址的数据类型。
Go语言条件控制语句
Go 语言提供了以下几种条件判断语句:
- if语句
- if…else语句
- switch语句
- select语句
前三者与传统编程语言类似。select 语句用于在多个通道操作中进行选择。它允许程序在多个通道上进行非阻塞的发送和接收操作。
select语句的语法如下:
select {
case <-channel1:
// 执行channel1接收操作
case data := <-channel2:
// 执行channel2接收操作,并将接收到的数据存储在data变量中
case channel3 <- data:
// 执行channel3发送操作,将data发送到channel3
default:
// 当没有任何case满足条件时执行default块
}
select语句的工作方式如下:
- 如果有任何一个case语句可以立即执行(即通道操作不会阻塞),则将执行该case语句。
- 如果有多个case语句可以立即执行,Go语言会随机选择一个case进行执行。
- 如果没有任何case可以立即执行,且存在default块,则会执行default块。
如果没有任何case可以立即执行,且没有default块,select语句将被阻塞,直到至少有一个case可以执行。
select语句常用于处理并发操作,例如同时监听多个通道的数据,或者在多个任务之间进行调度。它提供了一种简洁而有效的方式来处理并发情况下的选择操作。
select 语句的使用示例:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("Received", msg1)
case msg2 := <-c2:
fmt.Println("Received", msg2)
}
}
}
Go的函数
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {
// 函数体
}
函数可以接受零个或多个参数,并可以返回零个或多个值。参数和返回值可以是任何有效的Go语言类型。例如:
func swap(a, b int) (int, int) {
return b, a
}
函数可以像其他值一样被赋值给变量,并作为参数传递给其他函数。如:
func applyOperation(numbers []int, operation func(int) int) {
for i, num := range numbers {
numbers[i] = operation(num)
}
}
可以在函数内部定义匿名函数,也称为闭包函数。这些函数可以访问其外部函数的变量。
Go的指针
一个指针变量指向了一个值的内存地址。
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
指针变量声明格式如下:
var var_name *var_type
在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。
指针的代码示例:
a := 20 //声明实际变量
var ip *int //声明指针变量
ip = &a // 指针变量的存储地址
fmt.Printf("a 变量的地址是: %x\n", &a)
fmt.Printf("ip 变量储存的指针地址: %x\n", ip) // 指针变量的存储地址
fmt.Printf("*ip 变量的值: %d\n", *ip) // 使用指针访问值
Go的结构体
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:
type struct_variable_type struct {
member definition
member definition
...
member definition
}
定义了结构体类型,它就能用于变量的声明,语法格式如下:
variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
结构体的使用示例:
import "fmt"
type Person struct {
firstName string
lastName string
gender string
age int
}
func main() {
jon := Person{"Jon", "Snow", "Male", 18}
fmt.Println(jon)
}
Go的数组
声明数组:
var variable_name [size] variable_type
// 多维数组
var variable_name [size1][size2]...[sizeN] variable_type
初始化数组:
heroes := [5]string{"Steve Rogers", "Tony Stark", "Natasha Romanov"}
//可以用...自行推断数组的长度
casts := [...]string{"Chris Evans", "Robert Downey Jr.", "Scarlet Johnson"}
//如果设置了数组长度,可以指定下标来初始化元素
profiles := [5]string{1: "wearing an iron suit", 0: "super soldier", 2: "an agent"}
Go的映射
可以使用内建函数 make 或使用 map 关键字来定义 Map:
map_variable := make(map[KeyType]ValueType, initialCapacity)
例如:
capital := make(map[string]string, 2)
其中 KeyType 是键的类型,ValueType 是值的类型,initialCapacity 是可选的参数,用于指定 Map 的初始容量。Map 的容量是指 Map 中可以保存的键值对的数量,当 Map 中的键值对数量达到容量时,Map 会自动扩容。如果不指定 initialCapacity,Go 语言会根据实际情况选择一个合适的值。
也可以使用字面量创建 Map:
language := map[string]string{
"China": "Chinese",
"Japan": "Japanese",
"South Korea": "Korean",
}
获取元素:
l1, existed := language["South Korea"]//l1的值为键的映射值或该类型的零值,existed的值为true/false
修改元素:
language["America"] = "English"
获取 Map 的长度:
clen := len(capital)
遍历 Map:
for k, v := range capital {
fmt.Printf("%s:%s\n", k, v)
}
删除元素:
delete(capital, "China")
Go语言范围
Go语言中的 range 关键字可用于for循环中迭代数组、切片、通道或集合的元素。格式如下:
for k, v := range collection_name {
//operations to key and value
}
for k := range collection_name {
//operations to key
}
for _, v := range collection_name {
//operations to value
}
Go的类型转换
Go中的类型转换基本格式如下:
type_name(expression)
数值类型转换示例:
var i = 10
var f = float64(i)
将一个字符串转换成另一个类型,可以使用以下语法:
s := "0.002"
var n int
n, _ = strconv.Atoi(s)
以上代码将字符串变量 str 转换为整型变量 num。
参考:菜鸟教程