Golang继承中字段及方法的测试

本文详细测试了Golang中通过嵌入字段或指针实现继承的不同情形,验证了其设计思路及使用方法,包括结构内嵌入、匿名字段、方法传递等场景。
Golang采用嵌入字段来实现继承,由于实现上存在多种可能,这里进行测试,看看Golang的设计思路。

待考察的问题包括:
     嵌入的是结构,还是指针?
     嵌入部分是匿名字段,还是命名字段?
     方法是传值,还是传指针?

最终结论:
     可以嵌入字段,也可以嵌入指针,其特性吻合惯性思维
     无论字段是否指针,无论方法的接收者是否指针,在字段引用时都不区分指针

以下是测试过程

     一共4组不同情形的测试
          结构中有另一个结构,这是最简单的情形
          结构中有一个匿名结构,测试用类型代替字段名,或直接引用
          结构中有指针指向另一个结构
          结构中有匿名指针指向另一个结构

     每组测3个项目
          继承后的引用
          传值方法的继承
          传指针方法的继承

     故一共12个测试



第1组测试
     结构中有另一个结构,这是最简单的情形


package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    person Person // 有另一个字段
    school string
}


func main() {
    anna := new(Student)
    anna.person.name = "Anna"
    anna.person.tel = "12345678"
    //anna.school = "mit"
 
    fmt.Printf( "My name is %s, and my tel number is %s\n", anna.person.name, anna.person.tel)
 
}


第1.1组测试
     结构中有另一个结构,这是最简单的情形
     测试这种情况下方法的继承

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    person Person // 有另一个字段
    school string
}

//在person上面定义了一个传值的method
func (p Person) Hello() {
    fmt.Printf("My name is %s, and my tel number is %s\n", p.name, p.tel)
}
func main() {
    anna := new(Student)
    anna.person.name = "Anna"
    anna.person.tel = "2345678"
    //anna.school = "mit"
     
      // anna.Hello() // 这是不行的,非匿名字段不能直接引用
      anna.person.Hello()
     
    //fmt.Printf( "My name is %s, and my tel number is %s\n", anna.person.name, anna.person.tel)
}

结论:
     如果字段没有匿名,则相当于中间隔了一层,不能跨越去引用

第1.2组测试
     结构中有另一个结构,这是最简单的情形
     测试这种情况下方法的继承
     但是定义传指针的method

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    person Person // 有另一个字段
    school string
}

//在person上面定义了一个传指针的method
func (p * Person) Hello() {
    fmt.Printf( "My name is %s, and my tel number is %s\n", p.name, p.tel)
}
func main() {
    anna := new(Student)
    anna.person.name = "Anna"
    anna.person.tel = "345678"
    //anna.school = "mit"
    
       // anna.Hello() // 这是不行的,非匿名字段不能直接引用
      anna.person.Hello()
    
    //fmt.Printf( "My name is %s, and my tel number is %s\n", anna.person.name, anna.person.tel)
}

结论:
     没有问题,method传值或传指针没有区别

第2组测试
     结构中有一个匿名结构,测试用类型代替字段名,或直接引用

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    Person // 有一个匿名字段
    school string
}


func main() {
    anna := new(Student)
    anna.Person.name = "Anna" // 用类型代替字段名
    anna.tel = "123456789" // 或者直接引用
    //anna.school = "mit"
 
    fmt.Printf( "My name is %s, and my tel number is %s\n", anna.Person.name, anna.tel)
 
}



第2.1组测试
     结构中有一个匿名结构
     测试这种情况下方法的继承


package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    Person // 有另一个字段
    school string
}

//在person上面定义了一个传值的method
func (p Person) Hello() {
    fmt.Printf("My name is %s, and my tel number is %s\n", p.name, p.tel)
}
func main() {
    anna := new(Student)
    anna.Person.name = "Anna"
    anna.tel = "2345"
    //anna.school = "mit"
     
      anna.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
     
    //fmt.Printf( "My name is %s, and my tel number is %s\n", anna.person.name, anna.person.tel)
}

结论:匿名字段,相当于匿名结构直接嵌入,在同一层面

第2.2组测试
     结构中有一个匿名结构
     测试这种情况下方法的继承
     但是定义传指针的method

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    Person // 有另一个字段
    school string
}

//在person上面定义了一个传指针的method
func (p * Person) Hello() {
    fmt.Printf( "My name is %s, and my tel number is %s\n", p.name, p.tel)
}
func main() {
    anna := new(Student)
    anna.Person.name = "Anna"
    anna.tel = "345"
    //anna.school = "mit"
    
      anna.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
    
    //fmt.Printf( "My name is %s, and my tel number is %s\n", anna.person.name, anna.person.tel)
}

结论:
     传指针无影响

第3组测试
     结构中有指针指向另一个结构

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    person * Person // 指针指向一个字段
    school string
}


func main() {
    anna := new(Student)
    anna.person = new(Person) // 必须,否则panic
    anna.person.name = "Anna"
    anna.person.age = 22
    anna.person.tel = "12345"
    anna.school = "mit"
  
    fmt.Printf( "My name is %s, and my tel number is %s\n", anna.person.name, anna.person.tel)
  
}


第3.1组测试
     结构中有指针指向另一个结构
     测试方法的继承

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    person * Person // 指针指向一个字段
    school string
}

//在person上面定义了一个传值的method
func (p Person) Hello() {
    fmt.Printf("My name is %s, and my tel number is %s\n", p.name, p.tel)
}

func main() {
    anna := new(Student)
    anna.person = new(Person)
    anna.person.name = "Anna"
    anna.person.tel = "234567"
     
      anna.person.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
     
}

结论:
     非常正常的使用

第3.2组测试
     结构中有指针指向另一个结构
     测试方法的继承
     但是定义传指针的method

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    person * Person // 指针指向一个字段
    school string
}

//在person上面定义了一个传指针的method
func (p * Person) Hello() {
    fmt.Printf( "My name is %s, and my tel number is %s\n", p.name, p.tel)
}

func main() {
    anna := new(Student)
    anna.person = new(Person)
    anna.person.name = "Anna"
    anna.person.tel = "345678"
    
      anna.person.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
    
}

结论:
     指针无影响

第4组测试
     结构中有匿名指针指向另一个结构

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    * Person // 匿名指针指向一个字段
    school string
}


func main() {
    anna := new(Student)
    anna.Person = new(Person)
    anna.Person.name = "Anna"
    //anna.Person.age = 22
    anna.tel = "123"
    //anna.school = "mit"
 
    fmt.Printf( "My name is %s, and my tel number is %s\n", anna.Person.name, anna.tel)
 
}

结论:
     anna.Person = new(Person) 居然也行
     匿名相当于直接嵌入,在同一层面
     Golang似乎是尽量识别,如果有字段名,包括指针,则必须用字段名,如果是匿名,则可用匿名字段的类型
  
第4.1组测试
     结构中有匿名指针指向另一个结构
     测试方法的继承

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    * Person // 匿名指针指向一个字段
    school string
}


//在person上面定义了一个传值的method
func (p Person) Hello() {
    fmt.Printf("My name is %s, and my tel number is %s\n", p.name, p.tel)
}

func main() {
    anna := new(Student)
    anna.Person = new(Person)
    anna.Person.name = "Anna"
    anna.tel = "23456789"

     
      anna.Person.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
      anna.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
}

结论
     在同一层面,当然加上匿名指针也可

第4.2组测试
     结构中有匿名指针指向另一个结构
     测试方法的继承
     但是定义传指针的method

package main
import "fmt"

type Person struct {
    name string
    age int
    tel string
}

type Student struct {
    * Person // 匿名指针指向一个字段
    school string
}


//在person上面定义了一个传指针的method
func (p * Person) Hello() {
    fmt.Printf( "My name is %s, and my tel number is %s\n", p.name, p.tel)
}

func main() {
    anna := new(Student)
    anna.Person = new(Person)
    anna.Person.name = "Anna"
    anna.tel = "34"

    
      anna.Person.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
      anna.Hello() // 匿名字段,相当于匿名结构直接嵌入,在同一层面
}

结论:
     一样使用



<think>好的,用户想了解如何在Golang中附加结构体并读取其数据。首先,我需要明确“附加结构体”具体指什么。在Golang中,常见的结构体操作包括组合、嵌套、嵌入以及使用指针或值方法进行操作。可能用户指的是将结构体嵌入到另一个结构体中,或者通过某种方式关联两个结构体,以便访问数据。 接下来,我需要考虑如何解释结构体的组合和嵌入。Golang中没有继承,但可以通过嵌入结构体来实现类似的效果。例如,一个结构体可以嵌入另一个结构体,从而获得被嵌入结构体的字段方法。这可能就是用户所说的“附加”结构体。然后,关于读取数据,需要说明如何通过点操作符访问嵌入结构体的字段,或者如果使用嵌套结构体,可能需要指定中间字段名。此外,可能需要提到标签(tags)的使用,比如JSON或XML标签,用于序列化和反序列化数据,但用户的问题可能更偏向于结构体之间的组合而非数据格式的转换。 还需要考虑用户可能的实际应用场景,比如是否在构建一个具有扩展性的系统,或者处理某种数据存储问题。根据用户提供的引用,他们之前提到了MapReader结构体,其中包含缓存和头信息,可能用户想了解如何将不同的结构体组合在一起,比如将读取器与缓存结合,或者处理错误信息的结构体附加到主结构体上。另外,用户提供的引用中有关于错误处理的例子,使用指针接收器实现错误接口。这可能暗示用户对结构体方法以及接口实现也有兴趣,需要将这部分知识结合起来。需要确保回答的结构清晰,分步骤说明如何嵌入结构体,如何访问数据,可能还需要提到结构体标签的使用,以及通过方法操作结构体数据。同时,要给出代码示例,这样用户能更直观地理解。例如,展示一个包含嵌入结构体的例子,并演示如何访问其字段。 此外,需要注意用户提到的“附加”可能是指动态附加,但Golang是静态类型语言,无法在运行时动态附加结构体,但可以通过组合、接口或者使用map等方式来模拟。因此,需要明确说明Golang的结构体组合是编译时确定的,但可以通过设计模式来灵活使用。 最后,生成相关问题,帮助用户进一步学习,比如结构体嵌入与继承的区别,如何实现嵌套结构体的JSON序列化,或者结构体方法的指针与值接收器的区别等。</think>在Go语言中实现结构体的关联和数据读取,主要通过结构体组合、字段标签和反射机制实现。以下是具体实现方法: ### 一、结构体组合(嵌套) 通过嵌套结构体实现数据关联: ```go type Address struct { City string `json:"city"` Street string `json:"street"` } type User struct { Name string `json:"name"` Age int `json:"age"` Address Address `json:"address"` // 嵌套结构体 } func main() { user := User{ Name: "张三", Age: 30, Address: Address{ City: "北京", Street: "朝阳路", }, } // 读取嵌套数据 fmt.Println(user.Address.City) // 输出:北京 } ``` 这种组合方式在编译时确定类型关系,是Go语言推荐的结构设计方式[^3]。 ### 二、动态附加结构体 对于需要运行时动态附加数据的场景,可以使用以下方法: 1. **使用匿名结构体**: ```go type Base struct { ID int } func main() { extended := struct { Base Name string }{ Base: Base{ID: 1}, Name: "测试", } fmt.Println(extended.ID) // 输出:1 } ``` 2. **通过接口实现动态附加**: ```go type Attachable interface { Attach(key string, value interface{}) Get(key string) interface{} } type Container struct { data sync.Map } func (c *Container) Attach(key string, value interface{}) { c.data.Store(key, value) } func (c *Container) Get(key string) interface{} { val, _ := c.data.Load(key) return val } ``` ### 三、反射读取结构数据 使用`reflect`包读取结构体字段信息: ```go func PrintStruct(s interface{}) { val := reflect.ValueOf(s) typ := val.Type() for i := 0; i < val.NumField(); i++ { field := typ.Field(i) value := val.Field(i) fmt.Printf("%s (%s): %v\n", field.Name, field.Type, value.Interface()) } } ``` ### 四、结构体标签解析 结合反射读取字段标签: ```go type Example struct { Field string `customTag:"important"` } func main() { e := Example{"value"} t := reflect.TypeOf(e) field, _ := t.FieldByName("Field") fmt.Println(field.Tag.Get("customTag")) // 输出:important } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值