104.【GoLang基础】(四)

简介: 104.【GoLang基础】

3.切片类型 (slice)💥

切片的声明与数组类似,只不过是没有长度,var s []int,因为切片是对数组的引用,所以只声明而未初始化时切片的值为nil

在go语言中,切片(slice)是对数组的一个连续片段的引用,所以切片是一个引用类型,这个片段可以是整个数组,也可以是由起始和终止索引标识的一些项的子集;切片的内存分布是连续的,所以可以把切片当做一个大小不固定的数组。切片有三个字段的数据结构:指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)。

1. 获取全部
slice[:]
2.获取指定区域  左闭右开
slice[start:end]
3.从指定区域到尾部
slice[:end]
4.从头部到指定区域
silce[start:]
5.切片的三种定义:
  var strList []string //与数组的最大区别就是不要写参数,而数组需要写参数
  //生命整形切片
  var numList []int //与数组的最大区别就是不要写参数,而数组需要写参数
  //声明一个空的切片
  var numListEmpty = []int{} //与数组的最大区别就是不要写参数且左边不用编写类型,而数组需要写参数
package main // 这里的包一定要写成 main.
import "fmt"
/**
切片单独使用几乎没有什么用处,需要配合数组使用
*/
func main() { // 主函数
  //声明字符串切片
  var strList []string //与数组的最大区别就是不要写参数,而数组需要写参数
  //生命整形切片
  var numList []int //与数组的最大区别就是不要写参数,而数组需要写参数
  //声明一个空的切片
  var numListEmpty = []int{} //与数组的最大区别就是不要写参数且左边不用编写类型,而数组需要写参数
  // 输出三个切片
  fmt.Println(strList, " ", numList, " ", numListEmpty)
  fmt.Println("以上是输出三个切片")
  // 输出三个切片的大小
  fmt.Println(len(strList), " ", len(numList), " ", len(numListEmpty))
  fmt.Println("以上是输出三个切片的大小")
  //判定输出结果是否位不为空
  fmt.Println(strList == nil)
  fmt.Println(numList == nil)
  fmt.Println(numListEmpty == nil)
  fmt.Println("以上是判断切片是否为空")
  fmt.Println("以下是数组的指向")
  //  数组的第一中定义
  var a [3]int = [3]int{1, 2, 3}
  // 数组的第二种定义
  var b [3]int
  b[0] = 1
  // 数组的第三种定义方式
  c := [3]int{1, 2, 3}
  fmt.Println(a, " ", b, " ", c)
  fmt.Println("以下是切片指向数组")
  //  已经定义的切片指向数组
  numList = a[:]
  fmt.Println(numList)
  //  未定义的切片指向数组
  strlist1 := a[:]
  fmt.Println(strlist1)
  fmt.Println("以下是替换和追加")
  // 切片在指定索引处进行替换值
  numList[0] = 5
  fmt.Println(numList)
  // 切片在尾部追加
  numList = append(numList, 6)
  fmt.Println(numList)
}

4.函数类型 (func)💥

Go语言中的函数也是一种类型。

第一个小括号是入参的小括号,第二个小括号是返回的类型。如果为nil就可以省略
package main
// 参数为两个,且参数是返回一个值
func functionName1(a int, b int) (int) {
  return b + a
}
//  假如方法是空的话第二个参数可以省略
func functionName2(a int, b int) {
  println("第二个方法得数是: ", a, b)
}
func functionName3(a int, b int) (int, int) {
  return a, b
}
func main() {
  println("第一个方法得数是: ", functionName1(1, 3))
  functionName2(1, 2)
  var (
    sum1 int
    sum2 int
  )
  sum1, sum2 = functionName3(1, 2) // 假如有两个或者两个以上的返回值我们需要先接受,也可以使用匿名函数进行接受
  println("第三个方法得数是: ", sum1, " ", sum2)
}

5.管道类型 (channel)

Channel 是 Go 语言中被用来实现并行计算方程之间通信的类型。其功能是允许线程间通过发送和接收来传输指定类型的数据。其初始值是 nil。

var c1 chan 类型
c1 = make(chan 类型, 容量)
var c1 chan [value type]
c1 = make([channel type] [value type], [capacity])
  • [value type] 定义的是 Channel 中所传输数据的类型。

[channel type] 定义的是 Channel 的类型,其类型有以下三种:

  1. chan可读可写——“chan int” 则表示可读写 int 数据的 channel
  2. chan<-仅可写——“chan<- float64” 则表示仅可写64位 float 数据的 channel
  3. “<-chan仅可读——“<-chan int” 则表示仅可读 int 数据的 channel

[capacity] 是一个可选参数,其定义的是 channel 中的缓存区 (buffer)。如果不填则默认该 channel 没有缓冲区

(unbuffered)。对于没有缓冲区的 channel,消息的发送和收取必须能同时完成,否则会造成阻塞并提示死锁错误。对于

channel 的阻塞和非阻塞将在后面详细介绍。

(1).正常读和写

接受消息和发送消息

package main
func main() {
  var c1 chan int //定义一个channel类型的变量
  var jsxs int
  c1 = make(chan int, 100) //对这个channel的变量进行初始化
  // 我们向c1发送一个消息 (写入)
  c1 <- 20
  // 我们从c1中进行接受数据 (读取)
  jsxs = <-c1
  // 将我们接受的信息进行打印
  println(jsxs)
}
(2).发生死锁

只读不写或者只写不读会发生死锁或者读和写不同步都会导致死锁

读和写时间不一致,造成死锁反应

package main
import (
  "fmt"
  "time"
)
func main() {
  var c1 chan string
  c1 = make(chan string) //管道读和写
  func() {
    time.Sleep(time.Second * 2) //睡眠一会
    c1 <- "result 1"            //传入数据
  }()
  fmt.Println("received: '", <-c1, "' from c1") //读出数据
}

(3).如何解决死锁

第一种解决方法:

使用 go 语句进行并行计算

package main
import (
  "fmt"
  "time"
)
func main() {
  var c1 chan string
  c1 = make(chan string)
  go func() { //使用go语句
    time.Sleep(time.Second * 2)
    c1 <- "result 1"
  }()
  fmt.Println("received: '", <-c1, "' from c1")
}

通过 go 语句定义发送操作的方程在另一个线程并行运行,这样发送和接收操作就可以同时发生,从而能够解决死锁问题。

第二种解决方法:

package main
import (
  "fmt"
  "time"
)
func main() {
  var c1 chan string
  c1 = make(chan string, 1) //这里我们设置了一个长度为 1 的 buffer
  func() {
    time.Sleep(time.Second * 2)
    c1 <- "result 1"
  }()
  fmt.Println("received: '", <-c1, "' from c1")
}

为 channel 添加一个缓冲区(buffer),这样只要 buffer 没有用尽,阻塞就不会发生,死锁也不会发生。

“不要用共享来完成通信,而是用通信来完成共享” 说的就是推荐使用channel来完成协程之间的同步和通信等需求,而不是使用加锁,虽然GO也提供了完善的锁机制。

相关文章
|
编译器 Go Windows
104.【GoLang基础】(一)
104.【GoLang基础】
61 0
|
存储 编译器 Go
104.【GoLang基础】(七)
104.【GoLang基础】
70 0
|
Java 编译器 Go
104.【GoLang基础】(二)
104.【GoLang基础】
58 0
|
大数据 编译器 Go
104.【GoLang基础】(三)
104.【GoLang基础】
88 0
|
5月前
|
Go
|
5月前
|
监控 安全 Go
|
5月前
|
存储 Java Go
|
5月前
|
存储 JSON 数据库连接
|
5月前
|
存储 Java Go
|
中间件 Go API