Go语言的常用基础

2023年 12月 30日 64.3k 0

一、核心特性

Go语言有一些让人影响深刻的核心特性核心特性,比如:以消息传递模式的并发、独特的_符号、defer 、函数和方法、值传递等等,可以查看这篇文章《Go语言-让我印象深刻的13个特性》。首先要记住一些核心特性的用法。

1.Goroutine

  • 协程:独立的栈空间,共享堆空间,比线程更轻量。
  • 线程:一个线程上可以跑多个协程。
  • Go语言独有的协程,让程序员非常方便的使用并发编程,从而保留更多的心智去思考业务和创新。笔者认为这一点是Go语言最大的特性。

Goroutine就是这种协程特性的实现。Goroutine 是通过通信来共享内存,而不是共享内存来通信。通过共享内存来控制并发,会使编程变得更复杂,容易引入更多的问题。

Goroutine是由Go的运行时调度和管理。Go程序会智能地将 Goroutine 中的任务合理地分配给每个CPU,它在语言层面已经内置了调度和上下文切换的机制,不需要程序员去操作各种方法实现调度。

在Go语言中,当需要让某个任务并发执行时,只需要把这个任务包装成一个函数,开启一个Goroutine去执行就可以了。如下,只需要在调用函数时,在前面加上go关键字。

func hello_go() {
  fmt.Println("hello go!!!")
}

func main() {
    go hello_go()
    fmt.Println("main done!!!")
    time.Sleep(time.Second)
}

2.接口

在Go语言中接口interface是一种类型。Go语言的接口比较松散,只要是实现了接口定义的方法,就是实现了这个接口,无需使用implement等关键字去声明。

定义接口:

// 定义接口
type Sayer interface {
  say()
}
// 定义结构体
type dog struct {
}
type cat struct {
}
// 定义方法
func (d dog) say() {
  fmt.Println("狗叫")
}
func (c cat) say() {
  fmt.Println("猫叫")
}

空接口可以存储任意类型:

// 比如定义一个map类型的对象
var obj = map[string]interface{}

使用类型断言判断空接口中的值:

// x:表示类型为interface{}的变量
// T:表示断言x可能是的类型。
x.(T)
func main() {
  var x interface{}
  x = 123
  //v, ok := x.(int)
  v, ok := x.(string)
  if ok {
    fmt.Println(v)
  } else {
    fmt.Println("类型断言失败")
  }
}

接口特性:

  • 接口类型变量能够存储所有实现了该接口的实例。 如下,Sayer类型的变量能够存储dog和cat类型的变量。
// 定义接口
type Sayer interface {
  say()
}
// 定义结构体
type dog struct {
}
type cat struct {
}
// 定义方法
func (d dog) say() {
  fmt.Println("狗叫")
}
func (c cat) say() {
  fmt.Println("猫叫")
}

func main(t *testing.T) {
  var x Sayer // 声明一个接口类型的变量
  c := cat{}  // 实例化cat
  d := dog{}  // 实例化dog
  x = c       // cat赋值给接口类型
  x.say()     // 打印:猫叫
  x = d       // dog赋值给接口类型
  x.say()     // 打印:狗叫
}
  • 一个类型可以同时实现多个接口,接口间彼此独立。
// 定义接口
type Sayer interface {
  say()
}
type Mover interface {
  move()
}

// 定义结构体
type dog struct {
}

// 定义方法
func (d dog) say() {
  fmt.Println("狗叫")
}
func (d dog) move() {
  fmt.Println("狗移动")
}

func main(t *testing.T) {
  var x Sayer
  var y Mover

  var d = dog{}
  x = d
  y = d

  x.say()
  y.move()
}
  • 使用值接收者实现接口 和 使用指针接收者实现接口 有什么区别?值接受者实现时 可以用 指针类型赋值过去,但 指针接受者实现时 无法用 值类型赋值过去。
// 定义接口
type Mover interface {
  move()
}
type Sayer interface {
  say()
}

// 定义结构体
type dog struct {
}

// 定义方法
func (d *dog) say() {
  fmt.Println("狗叫")
}
func (d dog) move() {
  fmt.Println("狗移动")
}

func TestProgram(t *testing.T) {
  var x Sayer
  var y Mover

  //var d = dog{}
  var d = &dog{}
  x = d        // x不可以接收 dog类型,因为golang 不会 将值类型 转换 为指针类型
  y = d     // y可以接受  *dog类型,因为golang 会 将指针类型 转换 为值类型

  x.say()
  y.move()
}

3.下划线

_是特殊标识符,用来忽略结果。

buf := make([]byte, 1024)
f, _ := os.Open("/Users/***/Desktop/text.txt")

4.Go语言中的指针

  • &:用于获取变量的地址,其实就是所谓的指针类型**(地址类型)
  • :用于获取指针所指向的值*

func main() {
  a := 10
  fmt.Printf("type of a: %Tn", a)
  b := &a // 取变量a的地址,将指针保存到b中
  fmt.Printf("type of b: %Tn", b)
  c := *b // 取出 指针b 所指向的值
  fmt.Printf("type of c: %Tn", c)
  fmt.Printf("value of c: %vn", c)
}

5.new和make的区别

  • 二者都是用来做内存分配的。
  • make只用于slice、map、channel的初始化,返回的还是这三个引用类型本身。这里的引用有别于指针,他是对 slice、map、channel 值的间接访问,并不是一个指向 slice、map、channel 的指针。
  • new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。指针是一个变量,存储了值的内存地址。

6.defer延迟调用

关键字 defer 用于注册延迟调用。这些调用直到 return 前才被执。可以用来做资源清理,常用来关闭资源。defer 是先进后出。

func main() {
  arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  for _, v := range arr {
    defer fmt.Println("循环:", v)
  }
  fmt.Println("主流程跑完")
  time.Sleep(time.Second * 3)
  // 等待3秒后,执行defer,输出时先输出10,最后输出1,因为是先进后出
}

二、常用类型和内置函数

1.常用类型

bool                                // 布尔
int, int8, int16, int32, int64      // 整数
uint, uint8, uint16, uint32, uint64 // 0 和正整数
float32, float64                    //浮点数
string                              // 字符串
complex64, complex128               // 数学里的复数
array     // 固定长度的数组
struct    // 结构体
string    // 字符串
slice     // 序列数组
map       // 映射
chan      // 管道
interface // 接口 或 任意类型
func      // 函数

2.常用内置函数

append          // 追加元素到数组
copy            // 用于复制和连接slice,返回复制的数目
len             // 求长度,比如string、array、slice、map、channel
cap             // capacity是容量的意思,用于返回某个类型的最大容量(只能用于切片和 map)
delete          // 从map中删除key对应的value
panic           // 抛出异常(panic和recover:用来做错误处理)
recover         // 接受异常
make            // 分配内存,返回Type本身(只能应用于slice, map, channel)
new             // 分配内存,主要用来分配值类型,比如int、struct。返回指向Type的指针
close           // 关闭channel

三、变量、常量

// 申明变量
var name string

// 申明常量
const pi = 3.1415
const e = 2.7182
// 或
const (
        pi = 3.1415
        e = 2.7182
    )

// 申明并且初始化
n := 10

四、数据结构

1.数组

数组的长度固定:

var arr1 = [5]int{1, 2, 3, 4, 5}
// 或
arr2 := [...]struct {
  name string
  age  int8
}{
  {"yangling", 1},
  {"baily", 2},
}

2.切片

切片的长度不固定:

// 1.声明切片
var s1 []int
s2 := []int{}
var s3 = make([]int, 0)

// 向切片中添加元素
s1 = append(s1, 2, 3, 4)

// 从切片中按照索引获取切片
s1[low:high]

// 循环
for index, element := range s1 {
  fmt.Println("索引:", index, ",元素:", element)
}

3.Map

scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["李四"] = 100

userInfo := map[string]string{
  "username": "baily",
  "password": "111111",
}

// 如果key存在ok 为true,v为对应的值;
// 如果key不存在ok 为false,v为值类型的零值
v, ok := scoreMap["李四"]
if ok {
  fmt.Println(v)
} else {
  fmt.Println("查无此人")
}

// 循环
for k, v := range scoreMap {
  fmt.Println(k, v)
}

//将王五从map中删除
delete(scoreMap, "王五")

4.结构体

不同的使用方式,可能返回指针,也可能返回值。

// 定义结构体
type Student struct {
  name string
  age  int
}

func main() {
  // 使用结构体

  // 方式1,返回的是值
  var stu1 Student
  stu1.name = "baily"
  stu1.age = 1
  fmt.Println("baily1:", stu1)

  // 方式2,返回的是值
  var stu2 = Student{
    name: "baily",
    age:  1,
  }
  fmt.Println("baily2:", stu2)

  // 方式3,返回的是指针
  stu3 := &Student{
    name: "baily",
    age:  1,
  }
  fmt.Println("baily3指针:", stu3)
  fmt.Println("baily3值:", *stu3)

  // 方式4,返回的是指针
  var stu4 = new(Student)
  stu4.name = "baily"
  stu4.age = 1
  fmt.Println("baily4指针:", stu4)
  fmt.Println("baily4值:", *stu4)

}

五、流程控制

流程控制包括:if、switch、for、range、select、goto、continue、break。主要记下select,其他的跟别的语言类似。主要用于等待资源、阻塞等待等等。

select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

func main() {
var c1 = make(chan int)
go func() {
time.Sleep(time.Second * 10)
c1

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论