go基础语法之关键字
go语言是2007年在google公司诞生的,是基于编译、垃圾收集和并发的编程语言,专门针对多处理器系统应用程序的编程进行了优化。
go优势:
自带并发支持,语言层面支持并发,实现简单。
自动垃圾回收机制。
可直接编译成机器码,不依赖其它库,直接运行即可部署。
丰富的标准库。25个关键字,内嵌C语法支持。
跨平台。
go语言25个关键字
package:包
import:导入包
func:用于函数定义
go:并发执行
chan:定义channel
if:选择结构
else:选择结构
return:返回
switch:选择结构
case:选择结构标签
default:用于选择结构的默认选项(switch、select)
select:go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
for:循环语句
continue:跳过本次循环
break:break用于跳出循环
goto:跳转语句
defer:延迟执行函数
type:定义类型
var:定义变量
interface:定义接口
struct:定义结构体
const:定义常量
map:map类型
range:遍历slice、map等结构元素
fallthrough:case加上它,程序会继续执行下一条,不会判断下一条case的值
go使用包 package 来管理定义模块,使用 import 关键字来导入go自带的包和我们自定义的包。
在项目中新建api目录,定义a.go文件
package api
import "fmt"
//函数名首字母大写表示对外开放函数,如果小写,只能当前包内调用
func A() {
fmt.Println("A") //对外暴露函数A,打印A
}
go中函数名首字母大写表示对外开放函数,如果小写,只能当前包内调用。
main函数调用函数A,需要import中导入api包。
(go文件中存在main函数,当前package必须指定为main包)
package main
import (
"awesomeProject/api" //导入自定义包(自定义包需在gopath目录下)
"fmt" //引入go标准库fmt
)
func main() {
fmt.Println("打印A")
}
import也可导入匿名包, _ "包名"
导入匿名包(下划线表示匿名),即使不使用,也能正常运行。
package main
import (
_ "aa/lib1"
as "aa/lib2" 起as别名
. "aa/lib3" lib3包里面的方法都属于当前main包里面的方法
)
go语言并发通过goroutine(轻量级线程,也叫做协程)实现,属于用户态线程。由go 运行时管理。
go 函数名(参数列表)
package main
import (
"fmt"
"time"
)
func main() {
go fmt.Println("C")
time.Sleep(3)
//调用匿名函数
go func() {
fmt.Println("匿名函数")
}()
}
go语言中为解决数据资源的同步问题,引入了通信机制——通道,为多个goroutine之间提供数据资源共享。
通道创建语法:name := make(chan type, num)
type指数据类型。
num指存放数量上限。
make是内置函数方法,它为切片、集合和通道分配内存和初始化。
通道创建示例:
ch := make(chan int)。 创建无缓冲通道,要求发送和接收操作同时准备好,否则阻塞。
ch := make(<-chan int)。创建只读通道(单向通道)。
ch := make(chan<- int)。创建只写通道(单向通道)。
ch := make(chan int, 10)。创建缓冲通道,容量为10。(带缓冲通道,写入时通道中数据长度不大于缓冲长度,就不会阻塞。读取带缓冲通道时,如果通道没数据,程序依然会阻塞)
在通道里面写入和读取数据需要由 <-
操作符实现:
通道变量在 <-
操作符左边,往通道写入数据;
通道变量在 <-
操作符右边,则是读取通道数据。
见如下示例代码:
func f1() {
//带缓冲通道,写入时通道中数据长度不大于缓冲长度,就不会阻塞。读取带缓冲通道时,如果通道没数据,程序依然会阻塞
ch := make(chan int, 1)
ch <- 1
go func() {
v := <-ch
fmt.Println("value=", v)
}()
//go语言中程序会优先执行主线程,主线程执行完毕后,程序会立即退出。
所以加了time.Sleep让主线程休眠,让匿名函数打印值。
time.Sleep(5 * time.Second)
fmt.Println("0")
}
func f2() {
//通道是引用类型,需要使用 make 进行创建
ch := make(chan int) // 创建一个整型类型的通道
go func() {
//阻塞接收数据
v := <-ch
fmt.Println(v)
}()
time.Sleep(5 * time.Second)
// 尝试将0通过通道发送
ch <- 1
fmt.Println("0")
}
go语言提供了一种称为接口(interface)的数据类型,它代表一组方法的集合。
接口语法:
接口使用关键字type
和interface
定义,接口方法只需设置方法名称、参数名称和数据类型、返回值的数据类型,无需在接口中编写方法的业务功能,而方法的业务功能由结构体方法实现。
type interface_name interface {
method1(parameter) [returnType]
method2(parameter) [returnType]
method3(parameter) [returnType]
......
methodN(parameter) [returnType]
}
接口名和方法名首字母都大写,则对外暴露。
type actions interface {
//无参,无返回值
a()
//无参,有返回值
b() (int, int)
//有参,无返回值
c(t1 string, t2 int)
//有参,有返回值
d(t1 int) (int)
}
必须实现了所有接口的方法才算是实现了这个接口。(go没有java中重写、继承。只有多态)
接口示例代码如下:
package main
import "fmt"
type actions interface {
execute()
setname(name string)
}
// 定义结构体
type task struct {
name string //任务名属性
}
func (t *task) execute() {
fmt.Println("执行任务名称:", t.name)
}
func (t *task) setname(name string) {
t.name = name
fmt.Println("name=", name)
}
func main() {
f11()
}
func f11() {
//定义接口变量
var a actions
//结构体实例化
b := task{name: "sql脚本"}
//结构体实例化变量的指针(内存地址)赋值给接口变量
a = &b
a.execute()
a.setname("自动部署")
a.execute()
fmt.Println("打印任务名:", b.name)
}
结果输出:
执行任务名称: sql脚本
name= 自动部署
执行任务名称: 自动部署
打印任务名: 自动部署
go语言的集合称为映射(map),是一种无序的键值对key、value的集合。
//go方法内声明变量必须使用,否则编译不通过
//:= 只能够用在函数体内声明
package main
import "fmt"
func f12() {
//方式一:只定义
var m1 = map[string]int{}
m1["a"] = 1
fmt.Printf("集合m1: %v\n", m1)
//方式二:定义并赋值
var m2 = map[string]int{
"b": 2,
}
fmt.Printf("集合m2: %v\n", m2)
//方式三:使用make函数定义
m3 := make(map[string]int)
m3["c"] = 3
fmt.Printf("集合m3: %v\n", m3)
}
func main() {
f12()
}
切片是一种比较特殊的数据结构,切片可理解为动态数组,并根据切片中的元素自动调整切片长度。
定义:
var array []int
。声明array是一个切片,但是并没有给array分配空间。
var array = []int{1, 2}
。定义切片并赋值。
array := make([]int, 10)
。使用make()定义切片,开辟了10个空间,默认值是0。
示例代码如下:
package main
import "fmt"
func f123() {
//定义切片并赋值
var array = []int{1, 2}
//使用make()定义切片
array1 := make([]int, 10)
fmt.Printf("%v, 内存地址:%v\n", array, &array)
fmt.Printf("%v, 内存地址:%v\n", array1, &array1)
//新增切片元素
array = append(array, 3, 4, 5)
fmt.Println("数组元素:", array)
//截取切片元素
//截取第二个到第三个元素(从下标1开始取,不包含下标2)
s1 := array[1:2]
fmt.Println(s1)
//截取第一个到第三个元素
s2 := array[0:2]
fmt.Println(s2)
for index, value := range array {
fmt.Println("遍历数组 index= ", index, ", value=", value)
}
//复制切片
slice1 := []int{1, 2, 3, 9, 0}
slice2 := []int{4, 5, 6}
copy(slice1, slice2)
fmt.Println(slice1)
//切片长度与容量(当切片长度大于容量的时候,go语言将原有容量扩大至两倍,否则元素无法新增到切片中。)
a1 := make([]int, 3, 4)
fmt.Printf("值%v,长度%v,容量%v\n", a1, len(a1), cap(a1))
//第一次添加
a1 = append(a1, 5)
fmt.Printf("值%v,长度%v,容量%v\n", a1, len(a1), cap(a1))
//第二次添加,容量翻倍增长,增长为8
a1 = append(a1, 6)
fmt.Printf("值%v,长度%v,容量%v\n", a1, len(a1), cap(a1))
}
func main() {
f123()
}
结果:
[1 2], 内存地址:&[1 2]
[0 0 0 0 0 0 0 0 0 0], 内存地址:&[0 0 0 0 0 0 0 0 0 0]
数组元素: [1 2 3 4 5]
[2]
[1 2]
遍历数组 index= 0 , value= 1
遍历数组 index= 1 , value= 2
遍历数组 index= 2 , value= 3
遍历数组 index= 3 , value= 4
遍历数组 index= 4 , value= 5
[4 5 6 9 0]
值[0 0 0],长度3,容量4
值[0 0 0 5],长度4,容量4
值[0 0 0 5 6],长度5,容量8
参考资料
《GO语言编程从入门到实践》