golang内幕之组合

type Parent struct {
	Name string
	Age int
}

func (p Parent) String() string {
	return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}

func StructCombine_1() {
	var p1 = Parent{}
	fmt.Println(p1)

	var p2 = Parent{"name2", 2}
	fmt.Println(p2)

	var p3 = Parent{"name3",3,}
	fmt.Println(p3)

	var p4 = Parent{
		"name4",
		4}
	fmt.Println(p4)

	var p5 = Parent{
		"name5",
		5,
	}
	fmt.Println(p5)

	var p6 = Parent{Name:"name6"}
	fmt.Println(p6)

	var p7 = Parent{Age:7}
	fmt.Println(p7)
}

golang中的struct声明格式:

type StructName struct {
    FieldName type,
    ...
}

上面代码中,是结构体变量的定义,注意初始化的方法,可以指定字段名进行初始化,也可以按照所有字段的进行赋值,如果使用指定字段方式赋值,没有指定的字段按照默认值处理,特别注意:逗号有的地方是不能少的,请以上面代码为主,查看哪些在}之前仍旧有逗号的,这就是不能少的情况。

上面让Parent实现了String() string接口,目的是为了按照我们指定的格式打印输出Parent变量的内容。

type Parent struct {
	Name string
	Age int
}

type Child struct {
	Parent
	Sex string
	Age int
}

func (p Parent) String() string {
	return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}

func (c Child) String() string {
	return fmt.Sprintf("Name:%s, Sex:%s, p.Age:%d, c.Age:%d", c.Name, c.Sex, c.Parent.Age, c.Age)
}

func StructCombine_2() {
	var p = Parent{
		"P",
		18,
	}

	var c = Child{
		p,
		"f",
		20,
	}

	fmt.Println(p.Age)
	fmt.Println(c.Age)
	fmt.Println(c.Parent.Age)
}
=== RUN   TestStructCombine_2
18
20
18
--- PASS: TestStructCombine_2 (0.00s)
PASS

没什么大问题。

type Parent struct {
	Name string
	Age int
}

type ParentNew struct {
	Name string
	Age int
}

type Child struct {
	Parent
	ParentNew
	Sex string
	Age int
}

func (p Parent) String() string {
	return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}

func (p ParentNew) String() string {
	return fmt.Sprintf("Name:%s, Age:%d", p.Name, p.Age)
}

func (c Child) String() string {
	return fmt.Sprintf("Name:%s - %s, Sex:%s, p.Age:%d, c.Age:%d", c.Parent.Name, c.ParentNew.Name, c.Sex, c.Parent.Age, c.Age)
}

func StructCombine_3() {
	var p = Parent{
		"P",
		18,
	}

	var pn = ParentNew{
		"PN",
		19,
	}

	var c = Child{
		p,
		pn,
		"f",
		20,
	}

	fmt.Println(c.Name)
}

在这段代码中,我们定义的Child组合了Parent和ParentNew,而Parent和ParentNew都定义了字段Name,Child没有定义字段Name,现在我们想通过c.Name访问Name字段,到底会访问Parent.Name还是ParentNew.Name?

我们看看运行效果:

.\struct_combine.go:52:15: ambiguous selector c.Name

Compilation finished with exit code 2

编译报错了!很明显,我们这样写的代码,golang也不知道如何选择。

其实golang的做法很简单:通过组合继承已有struct的能力,如字段,如果组合者Child已经有对应字段,则优先访问Child的字段,如果Child没有,则去组合的Parent中查找,直到查找到为止,如果从组合中的多个Parent中都查找到,这样是符合语法要求的,编译期间就报错,也就是说具体访问的字段在编译期间就已经确定下来了。

上面代码是探讨字段的情况,下面探讨一下方法的情况:

type Base struct {

}

type Comb struct {
	Base
}

func (b Base) Work() {
	fmt.Println("Base Work")
}

func (c Comb) Work() {
	fmt.Println("Comb Work")
}

func StructCombMethod_1() {
	var b = Base{}
	var c = Comb{b}

	b.Work()
	c.Work()
}
=== RUN   TestStructCombMethod_1
Base Work
Comb Work
--- PASS: TestStructCombMethod_1 (0.00s)
PASS

很明显,编译期间,这些接受者都是已经确定的了。

type Base struct {

}

type Comb struct {
	Base
}

func (b Base) Work() {
	fmt.Println("Base Work")
}

func (c Comb) Work() {
	fmt.Println("Comb Work")
}

func (b Base) Play() {
	fmt.Println("Base Play")
	b.Work()
}

func StructCombMethod_2() {
	var b = Base{}
	var c = Comb{b}

	c.Play()
}
=== RUN   TestStructCombMethod_2
Base Play
Base Work
--- PASS: TestStructCombMethod_2 (0.00s)
PASS

由于Comb没有Play方法,c.Play()实际上是c.Base.Play(),此时接收者是Base,即b,自然结果就是

Base Play

Base Work

但其实Comb,即c是有Work方法的,按照支持多态的语言,是会调用Comb Work的,从这个也可以推断出:

golang是不支持多态的。

现在我们看看,Comb组合多个Base,看看会发生什么?

type Base struct {

}

type BaseNew struct {

}

type Comb struct {
	Base
	BaseNew
}

func (b Base) Work() {
	fmt.Println("Base Work")
}

func (b BaseNew) Work() {
	fmt.Println("BaseNew Work")
}

func (c Comb) Work() {
	fmt.Println("Comb Work")
}

func (b Base) Play() {
	fmt.Println("Base Play")
	b.Work()
}

func (b BaseNew) Play() {
	fmt.Println("BaseNew Play")
	b.Work()
}

func StructCombMethod_3() {
	var b = Base{}
	var bn = BaseNew{}
	var c = Comb{b,bn}

	c.Play()
}
.\struct_comb_method.go:45:3: ambiguous selector c.Play

Compilation finished with exit code 2

跟字段一样,因为不支持多态,必须是编译时确定下来的。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值