• golang 空结构体 struct{}


    定义的各种姿势
    原生定义
    a := struct{}{}
    1
    struct{} 可以就认为是一种类型,a 变量就是 struct {} 类型的一种变量,地址为 runtime.zerobase ,大小为 0 ,不占内存。

    重定义类型
    golang 使用 type 关键字定义新的类型,比如:

    type emptyStruct struct{}
    1
    定义出来的 emptyStruct 是新的类型,具有对应的 type 结构,但是性质 struct{} 完全一致,编译器对于 emptryStruct 类型的内存分配,也是直接给 zerobase 地址的。
    ————————————————
    var s struct{} 

    变量 size 是 0 ; fmt.Println(unsafe.Sizeof(s))

    本质上来讲,使用空结构体的初衷只有一个:节省内存,但是更多的情况,节省的内存其实很有限,这种情况使用空结构体的考量其实是:根本不关心结构体变量的值。

    作用1 :做set,map[string]struct{}
    由于struct{}是空,不关心内容,这样map便改造为set

    set := make(map[string]struct{})
    for _, value := range []string{"apple", "orange", "apple"} {
       set[value] = struct{}{}
    }
    fmt.Println(set)
    // Output: map[orange:{} apple:{}]

    map 和 struct {} 一般的结合姿势是这样的:

    // 创建 map
    m := make(map[int]struct{})
    // 赋值
    m[1] = struct{}{}
    // 判断 key 键存不存在
    _, ok := m[1]

    一般 map 和 struct {} 的结合使用场景是:只关心 key,不关注值。比如查询 key 是否存在就可以用这个数据结构,通过 ok 的值来判断这个键是否存在,map 的查询复杂度是 O(1) 的,查询很快。

    你当然可以用 map[int]bool 这种类型来代替,功能也一样能实现,很多人考虑使用 map[int]struct{} 这种使用方式真的就是为了省点内存,当然大部分情况下,这种节省是不足道哉的,所以究竟要不要这样使用还是要看具体场景。

    作用2:chan struct{}
    可以做退出

    func worker(i int, ch chan Work, quit chan struct{}) {
        for {
            select {
            case w := <-ch:
                // do something
            case <-quit:
                fmt.Println("worker", i, "quitting")
                quit = nil
            }
        }
    }

    还有其他情况,比如有时候使用channel,但并不需要附带任何数据。

    
    
    func worker(ch chan struct{}) {
        // Receive a message from the main program.
        <-ch
        println("roger")
        
        // Send a message to the main program.
        close(ch)
    }
    
    func main() {
        ch := make(chan struct{})
        go worker(ch)
        
        // Send a message to a worker.
        ch <- struct{}{}
        
        // Receive a message from the worker.
        <-ch
        println(“roger")
        // Output:
        // roger
        // roger
    }

    chan & struct{}
    channel 和 struct{} 结合是一个最经典的场景,struct{} 通常作为一个信号来传输,并不关注其中内容。chan 的分析在前几篇文章有详细说明。chan 本质的数据结构是一个管理结构加上一个 ringbuffer ,如果 struct{} 作为元素的话,ringbuffer 就是 0 分配的。

    chan 和 struct{} 结合基本只有一种用法,就是信号传递,空结构体本身携带不了值,所以也只有这一种用法啦,一般来说,配合 no buffer 的 channel 使用。

    // 创建一个信号通道
    waitc := make(chan struct{})
    
    // ...
    goroutine 1:
        // 发送信号: 投递元素
        waitc <- struct{}
        // 发送信号: 关闭
        close(waitc)
    
    goroutine 2:
        select {
        // 收到信号,做出对应的动作
        case <-waitc:
        }    

    这种场景我们思考下,是否一定是非 struct{} 不可?其实不是,而且也不多这几个字节的内存,所以这种情况真的就只是不关心 chan 的元素值而已,所以才用的 struct{}

    原文链接:https://blog.csdn.net/qiya2007/article/details/111502649

    https://blog.csdn.net/qiya2007/article/details/111502649

  • 相关阅读:
    开发人员维护测试数据库
    mybatis 自动生成 dao层 entity和xml时遇到的问题
    产品上线过程中犯下的错误
    leetcode: invert binary tree
    重构函数基本原则(持续更新)
    通过Mybatis获取mysql表中重复记录的方法
    Vmware 部分所学到的功能简写
    Vmware 主机锁定模式
    光纤卡网卡的区别以及HBA的常规定义-----引自百度百科
    存储基本概念(lun,volume,HBA,DAS,NAS,SAN,iSCSI,IPSAN)
  • 原文地址:https://www.cnblogs.com/youxin/p/16296407.html
Copyright © 2020-2023  润新知