doulianxing4015 2018-05-17 08:47
浏览 85
已采纳

函数名称前带下划线的结构标签

I am working with go, specifically QT bindings. However I do not understand the the use of leading underscores in the struct below. I am aware of the use of underscores in general but not this specific example.

type CustomLabel struct {
    core.QObject

    _ func() `constructor:"init"`
    _ string `property:"text"`
}

Does it relate to the struct tags?

  • 写回答

2条回答 默认 最新

  • doukong1897 2018-05-17 12:44
    关注

    Those are called blank-fields because the blank identifier is used as the field name.

    They cannot be referred to (just like any variable that has the blank identifier as its name) but they take part in the struct's memory layout. Usually and practically they are used as padding, to align subsequent fields to byte-positions (or memory-positions) that match layout of the data coming from (or going to) another system. The gain is that so these struct values (or rather their memory space) can be dumped or read simply and efficiently in one step.

    @mkopriva's answer details what the specific use case from the question is for.

    A word of warning: these blank fields as "type-annotations" should be used sparingly, as they add unnecessary overhead to all (!) values of such struct. These fields cannot be referred to, but they still require memory. If you add a blank field whose size is 8 bytes (e.g. int64), if you create a million elements, those 8 bytes will count a million times. As such, this is a "flawed" use of blank fields: the intention is to add meta info to the type itself (not to its instances), yet the cost is that all elements will require increased memory.

    You might say then to use a type whose size is 0, such as struct{}. It's better, as if used in the right position (e.g. being the first field, for reasoning see Struct has different size if the field order is different; and also Why position of `[0]byte` in the struct matters?), they won't change the struct's size. Still, code that use reflection to iterate over the struct's fields will still have to loop over these too, so it makes such code less efficient (typically all marshaling / unmarshaling process). Also, since now we can't use an arbitrary type, we lose the advantage of carrying a type information.

    This last statement (about when using struct{} we lose the carried type information) can be circumvented. struct{} is not the only type with 0 size, all arrays with 0 length also have zero size (regardless of the actual element type). So we can retain the type information by using a 0-sized array of the type we'd like to incorporate, such as:

    type CustomLabel struct {
        _ [0]func() `constructor:"init"`
        _ [0]string `property:"text"`
    }
    

    Now this CustomLabel type looks much better performance-wise as the type in question: its size is still 0. And it is still possible to access the array's element type using Type.Elem() like in this example:

    type CustomLabel struct {
        _ [0]func() `constructor:"init"`
        _ [0]string `property:"text"`
    }
    
    func main() {
        f := reflect.ValueOf(CustomLabel{}).Type().Field(0)
        fmt.Println(f.Tag)
        fmt.Println(f.Type)
        fmt.Println(f.Type.Elem())
    }
    

    Output (try it on the Go Playground):

    constructor:"init"
    [0]func()
    func()
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 kali环境运行volatility分析android内存文件,缺profile
  • ¥15 写uniapp时遇到的问题
  • ¥15 vs 2008 安装遇到问题
  • ¥15 matlab有限元法求解梁带有若干弹簧质量系统的固有频率
  • ¥15 找一个网络防御专家,外包的
  • ¥100 能不能让两张不同的图片md5值一样,(有尝)
  • ¥15 informer代码训练自己的数据集,改参数怎么改
  • ¥15 请看一下,学校实验要求,我需要具体代码
  • ¥50 pc微信3.6.0.18不能登陆 有偿解决问题
  • ¥20 MATLAB绘制两隐函数曲面的交线