前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >空结构体有什么作用?

空结构体有什么作用?

作者头像
公众号guangcity
发布2021-12-15 12:26:10
7690
发布2021-12-15 12:26:10
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)

空结构体有什么作用?

0.导语

本节将会介绍golang中空结构体的一些事,例如:实现set、通知chan,限制chan等,此外,会暴露出一些坑,接下来一起盘点一下。

1.空结构体

下方输出为0,对于空结构体大小为0,也就是不占用任何空间,这个特性在set与chan中颇受欢迎。

代码语言:javascript
复制
func main() {
 fmt.Println(unsafe.Sizeof(struct{}{}))
}

2.set

在go中没有像c++ stl那样自带set,需要使用map来实现。

代码语言:javascript
复制
type void struct{}
type set map[string]void

使用这种方式要比map[string]bool的set更优。当然,现在github上又一些比较成熟的set库,例如:golang-set。

3.chan

场景1: 通知任务完成

我们可以使用bool来表示,那么写法如下:

代码语言:javascript
复制
package main

import (
    "fmt"
    "time"
)

func worker(done chan bool) {
    fmt.Print("working...")
    time.Sleep(time.Second)
    fmt.Println("done")

    done <- true
}

func main() {

    done := make(chan bool, 1)
    go worker(done)

    <-done
}

对于通道来说,本身就可以用来传递数据,那么对于数据来说,当然是大小越小越好,像这种没有任何数据逻辑,这个数据也没有什么用的场景是可以用空结构体。

代码语言:javascript
复制
func worker(done chan struct{}) {
 fmt.Print("working...")
 // Send a value to notify that we're done.
 done <- struct{}{}
}

func main() {

 // Start a worker goroutine, giving it the channel to
 // notify on.
 done := make(chan struct{}, 1)
 go worker(done)

 // Block until we receive a notification from the
 // worker on the channel.
 <-done
}

场景2: 超时控制

使用空结构体+select语句。

代码语言:javascript
复制
// 利用 time.After 实现
func main() {
    done := do()
    select {
    case <-done:
        // logic
    case <-time.After(3 * time.Second):
        // timeout
    }
}

func do() <-chan struct{} {
    done := make(chan struct{}, 1)
    go func() {
        // do something
        // ...
        done <- struct{}{}
    }()
    return done
}

场景3: 限制最大并发数

限制最大并发数为2

代码语言:javascript
复制
limits := make(chan struct{}, 2)
for i := 0; i < 10; i++ {
    go func() {
        // 缓冲区满了就会阻塞在这
        limits <- struct{}{}
        do()
        <-limits
    }()
}

4.只包含方法的结构体

例如:

代码语言:javascript
复制
type Foo struct{}

func (f Foo) Eat() {
 fmt.Println("foo eat")
}

func (f Foo) Run() {
 fmt.Println("foo run")
}

5.一些问题

空结构体地址比较,会发现地址一样,但是一会是false、一会是true,那究竟空结构体能不能比较呢?

代码语言:javascript
复制
func main() {
 a := new(struct{})
 b := new(struct{})
 println(a, b, a == b)

 c := new(struct{})
 d := new(struct{})
 fmt.Println(c, d)
 println(c, d, c == d)
}

输出:

代码语言:javascript
复制
0xc00006cf57 0xc00006cf57 false
0x118c370 0x118c370 true
&{} &{}

在下面这篇文章中详细的解释了原因,这里简单说一下。

true解释:逃逸到堆上,空结构体则默认分配的是 runtime.zerobase 变量,是专门用于分配到堆上的 0 字节基础地址。因此两个空结构体,都是 runtime.zerobase,一比较当然就是 true 了。

false解释:分配到栈上。在 Go 编译器的代码优化阶段,会对其进行优化,直接返回 false。

https://eddycjy.com/posts/go/go-empty-struct/

本节完

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 空结构体有什么作用?
    • 0.导语
      • 1.空结构体
        • 2.set
          • 3.chan
            • 4.只包含方法的结构体
              • 5.一些问题
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档