注意
此篇适用于有一定编程语言基础的朋友阅读。
简介
Go(Golang)是Google在2007开发的一种开源编译型编程语言。是一种静态类型语言。Go语言具有“兼具Python等动态语言的开发速度和C或C++等编译型语言的性能和安全性”。
开发工具
开发工具有很多。可以使用Sublime、Textmate、Notepad++、Atom、IntelliJ IDEA等工具,本人这里是使用的IDEA,关于最新版Idea的安装和破解请阅读:《IntelliJ IDEA 2023.2.5安装教程》。
数据类型
类型
说明
描述
uint
无符号整型
uint、uint8、uint16、uint32、uint64等
int
有符号整型 int、int8、int16、int32等
byte
uint8的别名
等同uint8
rune
int32的别名
等同int32,表示一个unicode码
uintptr
指针
无符号整型,用于存放一个指针是一种无符号的整数类型
float
浮点型
float32、float64
string
字符串
"字符串"
complex 实数和虚数
complex64、complex128
Struct
结构化类型 可以包含字段和方法的结构体
Channel
通道类型
chan
Map
映射类型
键值对集合
Slice
切片类型
动态大小的字符序列。
Interface
接口类型
定义一组方法集的类型
func
函数类型 定义函数
[]arr
数组类型
[]string
const
常量类型
定义常量
类型定义
(1) var + 类型名称 + 数据类型
var num int16
(2) var ( 类型名称 + 数据类型 ) 。可以同时定义多个
var (
Name string
Age int16
Id string
)
(3)推导定义。 类型名称 + := 此方法只适用于方法等局部变量中。
aa := "string"
函数定义:
(1)func+空格 + 函数名称 +([参数]) ([返回值])+{函数体}
// 无参数与返回值
func method() {
fmt.Print("测试")
}
// 此参数与返回值
func Add(a int, b int) int {
return a + b
}
// 多返回值
func bb(a int, b int) (int, int) {
return a, b
}
// 返回值定义
func method2(a int, b int) (r int, w int) {
r=a
w=b
return
}
结构定义:首字母大写公共变量,小写为私有变量
type User struct {
Name string
Age int16
Id string
}
接口定义:
type IUser interface {
Method1()
Method2()
}
方法定义:注意方法与函数的不同,方法是与结构体绑定的行为。
func (user User) Method1() {
}
func (user User) Method2() {
}
控制流程
(1)if else
//单if
i := 3
if i == 3 {
}
//if else 格式
if i == 2 {
} else {
}
//if else if else 格式
if i == 1 {
} else if 3 == i {
} else {
}
(2) switch 语句:与case 配合使用。
func main() {
i := 2
switch i {
case 1:
//do something
case 2:
//do
default:
}
}
(3)for 循环
for i := 0; i <10; i++ {
}
numbers:=[]int {1,2,3,4,5,6}
for idx, value := range numbers {
fmt.Print(idx,value)
}
(4)defer : 执行滞后,在函数执行完成前执行。多个defer 遵循“先建后行”,最先定义的,倒叙执行。
defer func() {
fmt.Print("a")
}()
defer func() {
fmt.Print("b")
}()
defer func() {
fmt.Print("c")
}()
defer func() {
fmt.Print("d")
}()
//执行顺序为 d -> c -> b-> a
数组、切片、映射(键值对)
数组:数组是一个数据集合。定义时,需要指定其长度和数据类型。索引从0开始。
var arr [4]string
arr[0] = "aaaa"
arr[1] = "bbbb"
arr[2] = "aaaa"
arr[3] = "bbbb"
切片:底层数组的连续片段。需要用make()方法创建。
var arr =make([]string,4)
arr[0] = "aaaa"
arr[1] = "bbbb"
arr[2] = "aaaa"
arr[3] = "bbbb"
//追加
arr = append(arr, "ccc")
//复制
copy(targetArr,sourceArr)
映射(键值对):
映射是通过键来访问的无序元素编组。映射也被称为关联数组、字典或散列。格式定义:var mapV = make(map[keyType]valueType)
func Test() {
var foods = make(map[string]string)
//添加元素
foods["a"] = "红苹果"
foods["b"] = "黄香蕉"
foods["c"] = "橙橙子"
for key, value := range foods {
fmt.Print("key: "+key, " value:"+value+"\n")
}
//删除元素
delete(foods, "a")
fmt.Println("删除后,打印")
for key, value := range foods {
fmt.Print("key: "+key, " value:"+value+"\n")
}
}
公有与私有
go语言中约定,首字母大写为公有,首字母小写为私有。公有和私有的区别在于是否可被其他类或包使用。公有的属性定义是可以在其他地方进行引用(有的地方成为导出)。
type People struct {
Name string //公有
age int16 //私有
sex string //私有
}
指针引用与值引用
go语言在赋值过程中,是值赋值(副本),指针是指向内存地址的引用。用&表示,如&p,用表示数据,如p
var p test.People
p = test.People{
Name: "people name",
Age: 21,
Sex: "M",
}
p2 := p
fmt.Printf("%+v\n", p)
fmt.Printf("%+v\n", p2)
fmt.Printf("%p\n", &p)
fmt.Printf("%p\n", &p2)
p3 := &p
fmt.Printf("%+v\n", p)
fmt.Printf("%+v\n", *p3)
fmt.Printf("%p\n", &p)
fmt.Printf("%p\n", p3)
异常处理
//定义
err := errors.New("有些东西错误了")
if err!=nil {
fmt.Println(err)
}
//格式输出
name,age :="name error ","age error"
err := fmt.Errorf("the error : %v %v", name, age)
if err != nil {
fmt.Println(err)
}
//函数返回
func Test(i int) (int, error) {
if i != 0 {
return -1, fmt.Errorf("传入不是 0, %v", i)
}
return 1, nil
}
并发(Goroutine)
并发:同时处理众多事情。并行:同时做很多事情,在某一个时间点,处理多项事情。go语言中,用关键字 go + 执行体 表示。
//引用函数
go test.Add(1, 32)
//直接定义匿名函数
go func(a int, b int) {
fmt.Println(a + b)
}(32,23)
通道(channel)
通道(channel)是Go 语言中一种特殊的数据类型,通道本身就是并发安全的,可以通过它在多个 goroutine 之间传递数据。通道是Go 语言编程理念:“Do not communicate by sharing memory; instead, share memory by communicating”(不要通过共享数据来通信,而应该通过通信来共享数据。)
在Go语言中,通道(channel)是用于协程(goroutine)之间进行通信的重要机制。通道可以是有缓冲的(buffered)或无缓冲的(unbuffered)。
通道的缓冲大小决定了可以在通道中存储的元素个数。在创建通道时,可以指定通道的缓冲大小。
// 创建一个通道
ch := make(chan int)
// 开启一个goroutine向通道发送数据
go func() {
for i := 0; i < 15; i++ {
ch <- i // 发送数据到通道
time.Sleep(time.Second) // 每发送一个数据暂停一秒
}
close(ch) // 通道发送完毕后关闭
}()
// 使用range遍历通道,直到通道关闭
for v := range ch {
fmt.Println(v) // 打印通道接收到的值
}
单向通道:
在以参数传递过程中,可以根据需求进行控制,通道的只读与只写控制,由双向通道转为单向通道。
var c1 chan<- type_name
var c1 <-chan type_name
// 在函数体内只允许写入
func WriteChan(i chan<- int) {
i <- 1
i <- 2
i <- 3
}
// 在函数体内只允许读取
func ReadChan(i <-chan int) {
for v := range i {
fmt.Println(v)
}
}
缓存通道
func
main
() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
无缓冲通道的相关特性
发送操作:无缓冲通道上的发送操作将会阻塞,直到另一个goroutine在对应的通道上执行接收操作,这时值传送完成,两个goroutine都可以继续执行
接收操作:如果接收操作比发送操作先执行,接收方goroutine将阻塞,直到另一个goroutine在同一个通道上发送一个值
无缓冲通道的通信方式为"同步方式"
使用无缓冲通道进行的通信导致发送和接收goroutine同步化
因此,无缓冲通道也称为同步通道。当一个值在无缓冲通道上传递时,接收值后发送方goroutine才被再次唤醒
并发问题
goroutine的运行顺序是不一定的,因此当两个或多个goroutine并发地访问同一份数据的时候,就需要对访问进行排序,避免程序的执行发生问题。
好了,关于Go语言的基础篇,馆长就先介绍到这里。有兴趣的朋友可关注"IT技术馆"公众号,了解更多好玩且实用的技术分享。谢谢。