Golang 结构类型

1.简介

结构是已命名的元素序列,被称为字段,其中每一个元素都有一个名字和类型。 字段名可显示地指定(标识符列表)或隐式地指定(匿名字段)。 在结构中,非空白字段名必须是唯一的。

// 空结构
struct {}

// 带7个字段的结构
type STest struct {
	x, y int
	u float32
	_ float32  // 填充空白字段
	_ float64  // 填充空白字段
	A *[]int
	F func()
}

2.匿名字段

通过有类型而无显式字段名声明的字段为匿名字段,亦称为嵌入式字段或类型的嵌入。 嵌入的类型必须是一个类型名 T 或一个非接口类型的指针 *T, 且 T 本身不能为指针类型。未指定字段名的类型名可以作为字段名。

// 带类型为T1,*T2,P.T3和*P.T4的4个匿名字段的结构
struct {
	T1        // 字段名为T1
	*T2       // 字段名为T2
	P.T3      // 字段名为T3
	*P.T4     // 字段名为T4
	x, y int  // 字段名为x和y
}

以下为非法声明,因为字段名在结构类型中必须是唯一的:

struct {
	T     // 与匿名字段*T及*P.T相冲突
	*T    // 与匿名字段T及*P.T相冲突
	*P.T  // 与匿名字段T及*T相冲突
}

3.已提升的字段与方法

在结构 x 中,假设 f 是匿名字段的字段或者方法,如果 x. f 是合法的,则匿名字段的字段或方法 f 即为已提升的。

已提升的字段除了不能用作复合字面量赋值时的字段名外, 其行为如同结构体的一般字段。比如下面通过复合字面量构造结构体时,匿名字段的字段不能直接使用。

type T struct {
        x, y int
}

type Test struct{
        name string
        T					//匿名字段T
}

//错误的使用,报编译错误:unknown field 'x' in struct literal of type Test
test:=Test{name:"dablelv",x:1,y:2}

//错误的使用1,报编译错误:missing type in composite literal
test:=Test{"dablelv",{1,2}}

//正确的使用
test:=Test{"dablelv",T{1,2}}

给定结构类型 S 与名为 T 的类型,若 S 包含一个匿名字段 T 或 *T,则包含在结构 S 方法集中的已提升方法有:接收者为 T 或 *T 的方法。参考如下示例:

package main

import (
        "fmt"
)

type T struct {
        x, y int
}
func (t T) print(){
        t.x=666
        fmt.Printf("in print()\n")
}
func (t *T) printByPointer(){
        t.x=888
        fmt.Printf("in printByPointer()\n")
}

type Test struct{
        name string
        T
}

func main(){
        var test Test
        test.print()                    //Test调用提升方法T.print()
        fmt.Printf("%#v\n",test)

        test.printByPointer()           //Test调用提升方法(*T).printByPointer()
        fmt.Printf("%#v\n",test)

        (&test).print()                 //*Test调用提升方法T.print()
        fmt.Printf("%#v\n",test)

        (&test).printByPointer()        //*Test调用提升方法(*T).printByPointer()
        fmt.Printf("%#v\n",test)
}

程序输出结果:

in print()
main.Test{name:"", T:main.T{x:0, y:0}}
in printByPointer()
main.Test{name:"", T:main.T{x:888, y:0}}
in print()
main.Test{name:"", T:main.T{x:888, y:0}}
in printByPointer()
main.Test{name:"", T:main.T{x:888, y:0}}

将匿名字段T变为*T,同样可以调用接收者为T 或 *T 的已提升方法。参考代码如下:

type Test struct{
        name string
        *T
}

func main(){
        var test=Test{"",&T{0,0}}
        test.print()                    //Test调用提升方法T.print()
        fmt.Printf("%s %d %d\n",test.name,test.x,test.y)

        test.printByPointer()           //Test调用提升方法(*T).printByPointer()
        fmt.Printf("%s %d %d\n",test.name,test.x,test.y)

        (&test).print()                 //*Test调用提升方法T.print()
        fmt.Printf("%s %d %d\n",test.name,test.x,test.y)

        (&test).printByPointer()        //*Test调用提升方法(*T).printByPointer()
        fmt.Printf("%s %d %d\n",test.name,test.x,test.y)
}

运行结果:

in print()
 0 0
in printByPointer()
 888 0
in print()
 888 0
in printByPointer()
 888 0

4.字段标注

字段声明可后跟一个可选的字符串字面标注,成为字段的属性。 标注可通过反射接口获得,否则就会被忽略。

// 一个对应于时间戳协议缓存的结构.
// 标注字符串定义了协议缓存的字段号.
struct {
	microsec  uint64 "field 1"
	serverIP6 uint64 "field 2"
	process   string "field 3"
}

参考文献

[1] Go编程语言规范

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值