var 变量名 chan 变量类型
//channel是有类型的intChan 只能写入整数int
var intchan chan int
//mapChan用于存放map[int]string类型
var mapchan chan map[int]string
channel 必须初始化才能写入数据,即make后才能使用
//创建一个可以存放3个int类型的管道
intChan = make(chan int, 3)
声明的同时初始化
// 创建容量为 10 的 channel
mapchan := make(chan map[string]string, 10)
//看看intChan是什么
fmt.Printf("intChan 的值=%v intChan本身的地址=%p\n", intChan, &intChan)
intChan 的值=0xc000108080 intChan本身的地址=0xc00000a028
//intchan 指向存放数据的地址
int型
// 向管道写入数据
intChan<- 10
num := 211
intChan<- num
intChan<- 50
// 如果从channel取出数据后,可以继续放入
<-intChan
intChan<- 98
//注意点, 当我们给管道中写入数据时,不能超过其容量,数据放满后就不能再放入了
//从管道中读取数据
var num2 int
num2 = <-intChan
fmt.Println("num2=", num2)
fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 2, 3
num3 := <-intChan
num4 := <-intChan
fmt.Println("num3=", num3, "num4=", num4) // num3= 50 num4= 98
// 在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告 deadlock
//num5 := <-intChan
// fmt.Println( "num5=", num5)
//fatal error: all goroutines are asleep - deadlock!
使用内置函数close可以关闭channel,当channel关闭后,就不能再向channel写数据了,但是仍然
可以从该channel读取数据。
在 Go 中,我们可以使用内置函数 close 来关闭一个 channel。关闭一个 channel 后,就不能再向该 channel 中写入数据了,但仍然可以从该 channel 中读取数据。当从一个已经关闭的 channel 中读取数据时,会得到该 channel 类型的零值。
一个如何关闭channel的例子
package main
import "fmt"
func main() {
// 创建一个容量为 10 的整数类型的 channel
intChan := make(chan int, 10)
// 向 channel 中写入 5 个整数
for i := 1; i <= 5; i++ {
intChan <- i
}
// 关闭 channel
close(intChan)
// 从 channel 中读取所有整数
for {
// 从 channel 中读取一个整数
value, ok := <-intChan
// 如果 channel 已经关闭且里面没有数据了,就退出循环
if !ok {
break
}
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
// 再次从 channel 中读取数据,会得到零值
value, ok := <-intChan
fmt.Printf("Read a value from intChan after close: %d, %v\n", value, ok)
}
在这段代码中,我们创建了一个容量为 10 的整数类型的 channel intChan。然后我们向 intChan channel 中写入了 5 个整数。接着,我们使用 close 函数关闭了 intChan channel。最后,我们使用一个循环从 intChan channel 中读取所有整数,并将它们输出。在读取完所有整数后,我们再次从 intChan channel 中读取数据,这时会得到一个整数类型的零值和一个表示 channel 是否关闭的布尔值 false。
输出结果如下:
Read a value from intChan: 1
Read a value from intChan: 2
Read a value from intChan: 3
Read a value from intChan: 4
Read a value from intChan: 5
Read a value from intChan after close: 0, false
在 Go 中,当一个 channel 被关闭后,就不能再向该 channel 中写入数据了,否则会导致 panic。
下面是一个演示如何关闭 channel 的例子,同时在关闭后向该 channel 写入数据:
package main
import "fmt"
func main() {
// 创建一个容量为 10 的整数类型的 channel
intChan := make(chan int, 10)
// 向 channel 中写入 5 个整数
for i := 1; i <= 5; i++ {
intChan <- i
}
// 关闭 channel
close(intChan)
// 向已关闭的 channel 写入数据,会导致 panic
intChan <- 6
fmt.Println("write data to closed channel")
// 从 channel 中读取所有整数
for {
// 从 channel 中读取一个整数
value, ok := <-intChan
// 如果 channel 已经关闭且里面没有数据了,就退出循环
if !ok {
break
}
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
}
运行上面的代码会产生如下的 panic 信息:
panic: send on closed channel
goroutine 1 [running]:
main.main()
/path/to/main.go:15 +0x10b
exit status 2
可以看到,向已关闭的 channel 中写入数据会导致 panic,程序崩溃。
在这段代码中,我们创建了一个容量为 10 的整数类型的 channel intChan。然后我们向 intChan channel 中写入了 5 个整数。接着,我们使用 close 函数关闭了 intChan channel。接着,我们向已关闭的 intChan channel 中写入了整数 6,这时会导致 panic。最后,我们使用一个循环从 intChan channel 中读取所有整数,并将它们输出。
在 Go 中,可以通过 for 循环遍历 channel 中的数据,有以下几种方式:
// 创建一个容量为 3 的整数类型的 channel
intChan := make(chan int, 3)
// 向 channel 中写入 3 个整数
intChan <- 1
intChan <- 2
intChan <- 3
// 使用 range 关键字遍历 channel
for value := range intChan {
fmt.Printf("Read a value from intChan: %d\n", value)
}
在这段代码中,我们创建了一个容量为 3 的整数类型的 channel intChan,并向其中写入了 3 个整数。接着,我们使用 range 关键字遍历了 intChan channel 中的所有数据,并将它们输出。当 channel 被关闭后,使用 range 关键字遍历 channel 会自动退出循环。
// 创建一个容量为 3 的整数类型的 channel
intChan := make(chan int, 3)
// 向 channel 中写入 3 个整数
intChan <- 1
intChan <- 2
intChan <- 3
// 使用 for 循环和 select 语句遍历 channel
for {
select {
case value, ok := <-intChan:
// 如果 channel 已经关闭且里面没有数据了,就退出循环
if !ok {
return
}
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
}
在这段代码中,我们创建了一个容量为 3 的整数类型的 channel intChan,并向其中写入了 3 个整数。接着,我们使用 for 循环和 select 语句遍历了 intChan channel 中的所有数据,并将它们输出。当 channel 被关闭后,使用 for 循环和 select 语句遍历 channel 需要手动退出循环。
// 创建一个容量为 3 的整数类型的 channel
intChan := make(chan int, 3)
// 向 channel 中写入 3 个整数
intChan <- 1
intChan <- 2
intChan <- 3
// 使用 len 函数和 for 循环遍历 channel
for i := 0; i < len(intChan); i++ {
// 从 channel 中读取一个整数
value := <-intChan
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
在这段代码中,我们创建了一个容量为 3 的整数类型的 channel intChan,并向其中写入了 3 个整数。接着,我们使用 len 函数和 for
但是,这段代码会输出前两个整数,然后进入死循环,因为在for循环中使用了len(intChan)作为循环条件,但是在循环的过程中我们不断地从channel中读取数据,导致channel的长度始终保持为1,不会发生变化,从而导致for循环无法退出。
正确的做法是在循环条件中使用cap(intChan)函数获取channel的容量,如下所示:
// 创建一个容量为 3 的整数类型的 channel
intChan := make(chan int, 3)
// 向 channel 中写入 3 个整数
intChan <- 1
intChan <- 2
intChan <- 3
// 使用 len 函数和 for 循环遍历 channel
for i := 0; i < cap(intChan); i++ {
// 从 channel 中读取一个整数
value := <-intChan
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
这样就可以正确地遍历整个channel,输出所有的整数了。
package main
import "fmt"
func main() {
// 创建一个容量为 3 的整数类型的 channel
ch := make(chan int, 30)
// 向 channel 中写入 30 个整数
for i := 0; i < 30; i++ {
ch <- i
}
close(ch)
// 使用 len 函数和 for 循环遍历 channel
for i := 0; i < len(ch); i++ {
// 从 channel 中读取一个整数
value := <-ch
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
//for len(ch) > 0 {
// fmt.Println(<-ch)
//}
}
输出结果
Read a value from intChan: 0
Read a value from intChan: 1
Read a value from intChan: 2
Read a value from intChan: 3
Read a value from intChan: 4
Read a value from intChan: 5
Read a value from intChan: 6
Read a value from intChan: 7
Read a value from intChan: 8
Read a value from intChan: 9
Read a value from intChan: 10
Read a value from intChan: 11
Read a value from intChan: 12
Read a value from intChan: 13
Read a value from intChan: 14
如何使用len()得到正确结果
for len(ch) > 0{
}
package main
import "fmt"
func main() {
// 创建一个容量为 3 的整数类型的 channel
ch := make(chan int, 30)
// 向 channel 中写入 30 个整数
for i := 0; i < 30; i++ {
ch <- i
}
close(ch)
// 使用 len 函数和 for 循环遍历 channel
//for i := 0; i < len(ch); i++ {
// // 从 channel 中读取一个整数
// value := <-ch
// // 输出读取的整数
// fmt.Printf("Read a value from intChan: %d\n", value)
//}
for len(ch) > 0 {
value := <-ch
// 输出读取的整数
fmt.Printf("Read a value from intChan: %d\n", value)
}
}
结果如下
Read a value from intChan: 0
Read a value from intChan: 1
Read a value from intChan: 2
Read a value from intChan: 3
Read a value from intChan: 4
Read a value from intChan: 5
Read a value from intChan: 6
Read a value from intChan: 7
Read a value from intChan: 8
Read a value from intChan: 9
Read a value from intChan: 10
Read a value from intChan: 11
Read a value from intChan: 12
Read a value from intChan: 13
Read a value from intChan: 14
Read a value from intChan: 15
Read a value from intChan: 16
Read a value from intChan: 17
Read a value from intChan: 18
Read a value from intChan: 19
Read a value from intChan: 20
Read a value from intChan: 21
Read a value from intChan: 22
Read a value from intChan: 23
Read a value from intChan: 24
Read a value from intChan: 25
Read a value from intChan: 26
Read a value from intChan: 27
Read a value from intChan: 28
Read a value from intChan: 29
思考:channel的遍历中for len(ch) > 0{ } 能得到全部结果,然而for i := 0; i < len(ch); i++{ }只能得到一半结果
在使用for i := 0; i < len(ch); i++遍历channel时,由于channel在遍历过程中长度是动态变化的,因此可能只能读取到channel的一部分数据。具体来说,当channel中的数据量大于循环开始时的长度时,只能读取到前一半的数据。同时,如前面例子所示,当len(ch)=3时,会陷入死循环。
相比之下,for len(ch) > 0 {} 的循环条件是根据 channel 的实际长度来判断的,因此只要 channel 中还有元素,循环就会继续执行,直到 channel 中的所有元素都被读取完毕。因此,这种方式可以保证读取到全部的结果。
channel支持for–range的方式进行遍历,请注意两个细节
一个会导致deadlock错误的例子:
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
ch <- 2
ch <- 3
for i := range ch {
fmt.Println(i)
}
}
在这个例子中,我们创建了一个int类型的channel,并向该channel中写入了三个数据。然后我们使用for range循环遍历该channel,并输出其中的数据。但是由于我们没有关闭channel,当循环遍历完前三个数据后,程序会一直阻塞等待新的数据,导致deadlock错误。
fatal error: all goroutines are asleep - deadlock!
为了避免这种错误,我们可以使用close函数在遍历完所有数据后手动关闭channel,例如:
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for i := range ch {
fmt.Println(i)
}
}
在这个例子中,我们在循环遍历之前,使用close函数手动关闭了channel。这样,在遍历完所有数据后,for range循环会自动退出,避免了deadlock错误的发生。
package main
import "fmt"
func main() {
ch := make(chan map[string]string, 10) // 创建容量为 10 的 channel
// 向 channel 中输入 6 个数据
for i := 1; i <= 6; i++ {
data := make(map[string]string)
data["key"] = fmt.Sprintf("value %d", i)
ch <- data
}
// 从 channel 中取出并输出 6 个数据
for i := 1; i <= 6; i++ {
data := <-ch
fmt.Println(data["key"])
}
}
value 1
value 2
value 3
value 4
value 5
value 6
package main
import "fmt"
func main() {
mapchan := make(chan map[string]string, 10) // 创建容量为 10 的 channel
// 创建两个 map 变量 m1 和 m2,并向其中各写入 5 个数据
m1 := make(map[string]string, 20)
m1["key1"] = "value1"
m1["key2"] = "value2"
m1["key3"] = "value3"
m1["key4"] = "value4"
m1["key5"] = "value5"
m2 := make(map[string]string, 20)
m2["key6"] = "value6"
m2["key7"] = "value7"
m2["key8"] = "value8"
m2["key9"] = "value9"
m2["key10"] = "value10"
// 将 m1 和 m2 中的数据写入到 mapchan channel 中
mapchan <- m1
mapchan <- m2
// 从 mapchan channel 中取出并输出所有数据
for len(mapchan) > 0 {
m := <-mapchan
for k, v := range m {
fmt.Printf("%s: %s\n", k, v)
}
}
}
输出结果
key1: value1
key2: value2
key3: value3
key4: value4
key5: value5
key6: value6
key7: value7
key8: value8
key9: value9
key10: value10
在这段代码中,我们创建了一个容量为 10 的 mapchan channel,并创建了两个 map 变量 m1 和 m2,每个变量中各包含 5 个键值对。接下来,将 m1 和 m2 中的数据分别写入到 mapchan channel 中。然后使用一个循环从 mapchan channel 中读取数据,直到 channel 中没有剩余的数据。在循环体中,我们取出 channel 中的一个 map 变量 m,并遍历其中的键值对并输出它们。需要注意的是,在循环中我们使用 len(mapchan) > 0 来判断 channel 中是否还有剩余的数据,因为 len(mapchan) 表示 channel 中剩余的数据数量。由于我们在循环体中读取了所有数据,因此在循环结束后,mapchan channel 中不再有任何数据。
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
// 创建一个容量为 3 的 Person 类型的 channel
personChan := make(chan Person, 3)
// 向 channel 中写入 3 个 Person 类型的变量
person1 := Person{
"Tom", 18}
person2 := Person{
"Jerry", 19}
person3 := Person{
"Mike", 20}
personChan <- person1
personChan <- person2
personChan <- person3
// 从 channel 中取出并输出所有 Person 类型的变量
for len(personChan) > 0 {
person := <-personChan
fmt.Printf("Name: %s, Age: %d\n", person.Name, person.Age)
}
}
可以存放任意数据类型的channel:通过空接口实现
在下面这个例子中,我们将多个不同类型的数据写入了 dataChan channel,然后按照它们写入的顺序一个一个地取出来。输出结果显示了每个元素的值,其中包括整数、字符串、布尔值、浮点数、整数数组、空的映射、包含一个整数字段的结构体、空指针、字节数组以及包含字符串、整数和布尔值的接口切片。由于我们使用了 interface{} 类型,可以存储任何类型的数据。
package main
import "fmt"
func main() {
// 创建一个容量为 10 的 interface{} 类型的 channel
dataChan := make(chan interface{
}, 10)
// 向 channel 中写入 10 个任意类型的数据
dataChan <- 1
dataChan <- "hello"
dataChan <- true
dataChan <- 3.14
dataChan <- []int{
1, 2, 3}
dataChan <- make(map[string]int)
dataChan <- struct{
X int }{
X: 10}
dataChan <- nil
dataChan <- []byte("world")
dataChan <- []interface{
}{
"a", 1, false}
// 从 channel 中取出并输出所有数据
for len(dataChan) > 0 {
data := <-dataChan
fmt.Printf("%v\n", data)
}
}
1
hello
true
3.14
[1 2 3]
map[]
{
10}
<nil>
[119 111 114 108 100]
[a 1 false]
在 Go 中,我们可以使用空接口类型 interface{} 表示任意类型的值。当我们将一个具体类型的值存储到空接口类型的变量中时,这个变量会自动地被转换为 interface{} 类型。但是,在从空接口类型的变量中取出具体类型的值时,我们需要使用类型断言来将其转换回原来的类型。
下面是一个在空接口类型的 channel 中使用类型断言的例子:
package main
import "fmt"
func main() {
// 创建一个容量为 10 的空接口类型的 channel
dataChan := make(chan interface{
}, 10)
// 将多个不同类型的数据写入 channel 中
dataChan <- 1
dataChan <- "hello"
dataChan <- []int{
1, 2, 3}
dataChan <- struct{
X int }{
X: 10}
// 从 channel 中取出数据并进行类型断言
for len(dataChan) > 0 {
data := <-dataChan
switch v := data.(type) {
case int:
fmt.Printf("Got an int: %d\n", v)
case string:
fmt.Printf("Got a string: %s\n", v)
case []int:
fmt.Printf("Got an int slice: %v\n", v)
case struct{
X int }:
fmt.Printf("Got a struct: %+v\n", v)
default:
fmt.Printf("Got something else: %v\n", v)
}
}
}
在这段代码中,我们创建了一个容量为 10 的空接口类型的 channel dataChan。然后我们向 dataChan channel 中写入了 4 个不同类型的数据,包括 int、string、[]int 和 struct{X int}。最后,我们使用一个循环从 dataChan channel 中取出所有数据,并根据其类型进行类型断言。如果数据是 int 类型,我们就输出 "Got an int: " 和该值;如果数据是 string 类型,我们就输出 "Got a string: " 和该值;以此类推。
输出结果如下:
Got an int: 1
Got a string: hello
Got an int slice: [1 2 3]
Got a struct: {
X:10}
在这个例子中,我们使用了类型断言来将从 dataChan channel 中取出的值转换回原来的类型。由于我们在写入数据时将它们转换成了空接口类型,因此在取出数据时需要使用类型断言将它们转换回原来的类型。
文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目
文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析
文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat
文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集
文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception
文章浏览阅读358次。1.介绍图的相关概念 图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为: G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图
文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc
文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗
文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver
文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象
文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法
文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范