TypeOf().FieldAlign() 似乎没有文档中描述的功能,为什么?

TypeOf().FieldAlign() 似乎没有文档中描述的功能,看起来和 TypeOf().Align() 没什么区别,为什么?

package main

import (
    "fmt"
    "reflect"
)

var v = struct {
    a byte
    b int32
    c byte
    d int64
}{0, 0, 0, 0}

func main() {
    fmt.Printf("结构体大小:%v\n", reflect.TypeOf(v).Size())
    showAlign(v.a)
    showAlign(v.b)
    showAlign(v.c)
    showAlign(v.d)
}

func showAlign(i interface{}) {
    t := reflect.TypeOf(i)
    fmt.Printf("字段 %5v,大小:%v,对齐:%v,字段对齐:%v\n",
        t.Name(),
        t.Size(),
        t.Align(),
        t.FieldAlign(),
    )
}

输出结果:

结构体大小:24
字段 uint8,大小:1,对齐:1,字段对齐:1
字段 int32,大小:4,对齐:4,字段对齐:4
字段 uint8,大小:1,对齐:1,字段对齐:1
字段 int64,大小:8,对齐:8,字段对齐:8

共 7 个回复


snake117

你弄错了伙计。FieldAlign这个方法针对的是结构体的字段。

但showAlign(v.a)传递进去的就不是结构体的字段,而是单纯的基本类型的数据。

正确的用法是

TypeOf(v).Field(n).FieldAlign()

n为0、1、2或3

# 0

stevenldj

谢谢指点,不过 TypeOf().Field()没有FieldAlign()方法,只有一些属性,我试着用TypeOf().Field().Type.FieldAlign(),结果也是一样,但是我在Field()的属性列表中看到了Offset属性,试了一下,可以看到正确的偏移量,这就可以算出对齐信息了。代码如下:

// 前面代码省略 ...
func main() {
    t := reflect.TypeOf(v)
    fmt.Printf("结构体大小:%v\n", t.Size())
    for i := 0; i < t.NumField(); i++ {
        showAlign(t, i)
    }
}

func showAlign(v reflect.Type, i int) {
    sf := v.Field(i)
    fmt.Printf("字段 %5v,大小:%v,对齐:%v,字段对齐:%v,偏移:%v\n",
        sf.Type.Name(),
        sf.Type.Size(),
        sf.Type.Align(),
        sf.Type.FieldAlign(),
        sf.Offset,
    )
}

结果如下:

结构体大小:24
字段 uint8,大小:1,对齐:1,字段对齐:1,偏移:0
字段 int32,大小:4,对齐:4,字段对齐:4,偏移:4
字段 uint8,大小:1,对齐:1,字段对齐:1,偏移:8
字段 int64,大小:8,对齐:8,字段对齐:8,偏移:16
# 1

snake117

是我记错了。

TypeOf().Field()的结果不是Type类型是StructField。

FieldAlign适用于结构体的字段的Type类型。但是TypeOf().Field()得到的是StructField类型,它的Type字段就是结构体的字段的Type类型。

FieldAlign通常是用于这种:

ValueOf().Field().Type().FieldAlign()

也就是你得到的是Value类型而不是Type类型的值时,使用FieldAlign,如果得到的是Type类型(并且局限于结构体类型的Type)才能用Offset。

# 2

snake117

StructField的Type字段是结构体的字段的类型的Type类型,而不是结构体字段Type类型,这个Type字段没有包含“这是某个结构体的字段”这一属性,而是单纯的字段的类型的Type映射。

# 3

stevenldj

换成 ValueOf()结果还是一样:

func main() {
    fmt.Println(reflect.ValueOf(v).Field(0).Type().FieldAlign()) // 1
    fmt.Println(reflect.ValueOf(v).Field(1).Type().FieldAlign()) // 4
    fmt.Println(reflect.ValueOf(v).Field(2).Type().FieldAlign()) // 1
    fmt.Println(reflect.ValueOf(v).Field(3).Type().FieldAlign()) // 8
}
# 4

snake117

这我也搞不清楚了,楼主你给go开发组递交个request吧

# 5

stevenldj

不知道怎么递交 :P

# 6