在函数名称前加上带下划线的struct标记 [英] Go struct tags with underscore before function names

查看:116
本文介绍了在函数名称前加上带下划线的struct标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用go,特别是QT绑定.但是,我不理解以下结构中前导下划线的使用.我知道通常使用下划线,但不知道此特定示例.

I am working with go, specifically QT bindings. However, I do not understand 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"`
}

它与struct标签有关吗?

Does it relate to the struct tags?

推荐答案

由于空白标识符用作字段名称.

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的答案详细说明了问题中特定用例的用途.

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

警告提示::应谨慎使用这些空白字段(如类型注释"),因为它们会为此类结构的 all (!)值增加不必要的开销.这些字段不能被引用,但是它们仍然需要内存.如果您添加一个空白字段,其大小为8个字节(例如int64),则如果创建一百万个元素,则这8个字节将计数一百万次.因此,这是对空白字段的错误"使用:目的是向 type 本身(而不是其实例)添加元信息,但是代价是所有元素都需要增加内存

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.

然后您可能会说使用大小为0的类型,例如struct{}.最好将其用作正确的位置(例如,作为第一个字段,进行推理,请参见为什么[0] byte在结构中的位置很重要?),它们不会更改结构的大小.尽管如此,使用反射来遍历结构域的代码仍然必须遍历这些字段,因此这会使此类代码的效率降低(通常是所有编组/解组过程).而且,由于现在我们不能使用任意类型,因此我们失去了携带类型信息的优势.

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.

可以绕过最后一条语句(大约在使用struct{}时,我们丢失了所携带的类型信息). struct{}不是唯一的大小为0的类型,所有长度为0的数组也具有零大小(与实际元素类型无关).因此,我们可以通过使用要合并的类型的0大小的数组来保留类型信息,例如:

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"`
}

现在,此CustomLabel类型在性能上看起来比所讨论的类型好得多:它的大小仍为0.仍然可以使用Type.Elem()来访问数组的元素类型,如本例所示:

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())
}

输出(在转到游乐场上尝试):

constructor:"init"
[0]func()
func()

这篇关于在函数名称前加上带下划线的struct标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆