【Golang】关于Go中的struct{}
一、关于struct {}
struct是Go中的关键字,用于定义结构类型
1 2 3 4 | type User struct { Name string Age int } |
struct {} :表示struct类型
struct {} 是一种普通数据类型,一个无元素的结构体类型,通常在没有信息存储时使用。
优点是大小为0,不需要内存来存储struct {}类型的值。
struct {} {}:表示struct类型的值,该值也是空。
struct {} {}是一个复合字面量,它构造了一个struct {}类型的值,该值也是空。
1 2 3 4 5 6 7 8 9 10 11 12 | var set map [string] struct {} set = make( map [string] struct {}) // Add some values to the set: set[ "red" ] = struct {}{} set[ "blue" ] = struct {}{} // Check if a value is in the map: _, ok := set[ "red" ] fmt.Println( "Is red in the map?" , ok) _, ok = set[ "green" ] fmt.Println( "Is green in the map?" , ok) |
输出内容
1 2 | Is red in the map ? true Is green in the map ? false |
空结构体的宽度是0,占用了0字节的内存空间
1 2 | var s struct {} fmt.Println(unsafe.Sizeof(s)) // prints 0 |
由于空结构体占用0字节,那么空结构体也不需要填充字节。所以空结构体组成的组合数据类型也不会占用内存空间。
1 2 3 4 5 6 7 | type S struct { A struct {} B struct {} } var s S fmt.Println(unsafe.Sizeof(s)) // prints 0 |
二、chan struct{}
通过消息来共享数据是golang的一种设计哲学,channel则是这种哲理的体现。
golang中的空结构体 channel := make(chan struct{})
-
省内存,尤其在事件通信的时候。
-
struct零值就是本身,读取close的channel返回零值
1、通常struct{}类型channel的用法是使用同步
注意,channel对象一定要make出来才能使用
一般不需要往channel里面写数据,只有读等待,而读等待会在channel被关闭的时候返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package main import ( "time" "log" ) var ch chan struct {} = make( chan struct {}) func foo() { log.Println( "foo start" ); time.Sleep(3 * time.Second) log.Println( "foo close chan" ); close(ch) log.Println( "foo end" ); } func main() { log.Println( "main start" ); go foo() log.Println( "main wait chan" ); <-ch log.Println( "main end" ); } |
运行结果
1 2 3 4 5 6 | 2022/05/28 19:34:44 main start 2022/05/28 19:34:44 main wait chan 2022/05/28 19:34:44 foo start 2022/05/28 19:34:47 foo close chan 2022/05/28 19:34:47 foo end 2022/05/28 19:34:47 main end |
如果一开始就往 元素类型为 struct{} 的 chan 中写元素,则 main 中会立马收到信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package main import ( "time" "log" ) var ch chan struct {} = make( chan struct {}) func foo() { log.Println( "foo start" ); ch <- struct {}{} time.Sleep(3 * time.Second) log.Println( "foo close chan" ); close(ch) log.Println( "foo end" ); } func main() { log.Println( "main start" ); go foo() log.Println( "main wait chan" ); ret, ok := <-ch if ok { log.Println( "main recv info : " , ret); } else { log.Println( "main chan has closed" ); } log.Println( "main end" ); } |
运行结果
1 2 3 4 5 | 2022/05/28 19:35:41 main start 2022/05/28 19:35:41 main wait chan 2022/05/28 19:35:41 foo start 2022/05/28 19:35:41 main recv info : {} 2022/05/28 19:35:41 main end |
2、比较经典的例子就是用于stopChan作为停止channel通知所有协程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | type Server struct { serverStopChan chan struct {} stopWg sync.WaitGroup } func (s *Server) Stop() { if s.serverStopChan == nil { panic( "gorpc.Server: server must be started before stopping it" ) } close(s.serverStopChan) s.stopWg.Wait() s.serverStopChan = nil } func serverHandler(s *Server){ for { select { case <-s.serverStopChan: return default : // .. do something } } } |
3、带缓冲的chan struct{}数据读写
另外也可以定义带缓冲的channel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package main import ( "time" "log" ) var ch chan struct {} = make( chan struct {}, 2) func foo() { ch <- struct {}{} log.Println( "foo() 000" ); ch <- struct {}{} log.Println( "foo() 111" ); time.Sleep(5 * time.Second) log.Println( "foo() 222" ); close(ch) log.Println( "foo() 333" ); } func main() { var b struct {} log.Println( "main() 111" ); go foo() log.Println( "main() 222" ); a := <-ch log.Println( "main() 333" , a); b = <-ch log.Println( "main() 444" , b); c := <-ch log.Println( "main() 555" , c); } |
<-ch用来从channel ch中接收数据,这个表达式会一直被block,直到有数据可以接收。
从一个nil channel中接收数据会一直被block。(往nil channel中发送数据会一致被阻塞着。)
从一个被close的channel中接收数据不会被阻塞,而是立即返回,接收完已发送的数据后会返回元素类型的零值(zero value)。
如前所述,你可以使用一个额外的返回参数来检查channel是否关闭。
1 2 3 | x, ok := <-ch x, ok = <-ch var x, ok = <-ch |
如果OK 是false,表明接收的x是产生的零值,这个channel被关闭了或者为空。
- 作者:踏雪无痕
- 出处:http://www.cnblogs.com/chenpingzhao/
- 本文版权归作者和博客园共有,如需转载,请联系 pingzhao1990#163.com
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决
2019-05-28 【Java】3到5年开发常见的Java面试题
2019-05-28 【Linux】小米路由开启SSH访问权限
2015-05-28 PHP实现4种排序算法